

Analyzed bundle 'Sample Bundle' with 0 classes
[email protected]
Regards, Aruna
By the way my test cases are running in a pax-exam container. Is this an issue?.
Evgeny Mandrikov
<plugin> <artifactId>maven-antrun-plugin</artifactId> <version>${version.maven.antrunplugin}</version> <executions> <execution> <phase>prepare-package</phase> <configuration> <target xmlns:jacoco="antlib:org.jacoco.ant"> //this task is to provide class/src files locations for jacoco report generation <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml"> <classpath path="${project.build.directory}"/> </taskdef> <jacoco:report> <executiondata> <file file="${project.build.directory}/jacoco.exec"/> </executiondata> <structure name="Sample Tests"> <classfiles> <fileset dir="../core/target/classes"/> </classfiles> <sourcefiles encoding="UTF-8"> <fileset dir="../core/src"/> </sourcefiles> </structure> <html destdir="${project.build.directory}/site/jacoco"/> </jacoco:report> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.jacoco</groupId> <artifactId>org.jacoco.ant</artifactId> <version>${version.org.jacoco.ant}</version> </dependency> </dependencies> </plugin>
Search code, repositories, users, issues, pull requests...
Provide feedback.
We read every piece of feedback, and take your input very seriously.
Saved searches
Use saved searches to filter your results more quickly.
To see all available qualifiers, see our documentation .
- Notifications
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
jacoco-maven-plugin:report reports 0 classes #548
ctron commented Jun 14, 2017
Godin commented Jun 14, 2017 • edited
Sorry, something went wrong.
Godin commented Jun 14, 2017
No branches or pull requests
Change History
Snapshot build 0.8.12.202311090927 (2023/11/09), release 0.8.11 (2023/10/14), new features.
- JaCoCo now officially supports Java 21 (GitHub #1520 ).
- Experimental support for Java 22 class files (GitHub #1479 ).
- Part of bytecode generated by the Java compilers for exhaustive switch expressions is filtered out during generation of report (GitHub #1472 ).
- Part of bytecode generated by the Java compilers for record patterns is filtered out during generation of report (GitHub #1473 ).
- Instrumentation should not cause VerifyError when the last local variable of method parameters is overridden in the method body to store a value of type long or double (GitHub #893 ).
- Restore exec file compatibility with versions from 0.7.5 to 0.8.8 in case of class files with zero line numbers (GitHub #1492 ).
Non-functional Changes
- jacoco-maven-plugin now requires at least Java 8 (GitHub #1466 , #1468 ).
- JaCoCo build now requires at least Maven 3.5.4 (GitHub #1467 ).
- Maven 3.9.2 should not produce warnings for jacoco-maven-plugin (GitHub #1468 ).
- JaCoCo build now requires JDK 17 (GitHub #1482 ).
- JaCoCo now depends on ASM 9.6 (GitHub #1518 ).
Release 0.8.10 (2023/04/24)
- Agent should not require configuration of permissions for SecurityManager outside of its codeBase (GitHub #1425 ).
Release 0.8.9 (2023/03/31)
- JaCoCo now officially supports Java 19 and 20 (GitHub #1371 , #1386 ).
- Experimental support for Java 21 class files (GitHub #1386 ).
- Add parameter to include the current project in the report-aggregate Maven goal (GitHub #1007 ).
- Component accessors generated by the Java compilers for records are filtered out during generation of report. Contributed by Tesla Zhang (GitHub #1393 ).
- Agent should not open java.lang package to unnamed module of the application class loader (GitHub #1334 ).
- JaCoCo now depends on ASM 9.5 (GitHub #1299 , #1368 , #1416 ).
- JaCoCo build now requires JDK 11 (GitHub #1413 ).
Release 0.8.8 (2022/04/05)
- JaCoCo now officially supports Java 17 and 18 (GitHub #1282 , #1198 ).
- Experimental support for Java 19 class files (GitHub #1264 ).
- Part of bytecode generated by the Java compilers for assert statement is filtered out during generation of report (GitHub #1196 ).
- Branch added by the Kotlin compiler version 1.6.0 and above for "unsafe" cast operator is filtered out during generation of report (GitHub #1266 ).
- Improved support for multiple JaCoCo runtimes in the same VM (GitHub #1057 ).
- Fixed NullPointerException during filtering (GitHub #1189 ).
- Fix range for debug symbols of method parameters (GitHub #1246 ).
- JaCoCo now depends on ASM 9.2 (GitHub #1206 ).
- Messages of exceptions occurring during analysis or instrumentation now include JaCoCo version (GitHub #1217 ).
Release 0.8.7 (2021/05/04)
- JaCoCo now officially supports Java 15 and 16 (GitHub #1094 , #1097 , #1176 ).
- Experimental support for Java 17 class files (GitHub #1132 ).
- New formats parameter for Maven report goals to specify the generated report formats. Contributed by troosan. (GitHub #1175 ).
- Branch added by the Kotlin compiler version 1.4.0 and above for "unsafe" cast operator is filtered out during generation of report (GitHub #1143 , #1178 ).
- synthetic methods added by the Kotlin compiler version 1.5.0 and above for private suspending functions are filtered out (GitHub #1174 ).
- Branches added by the Kotlin compiler version 1.4.20 and above for suspending lambdas are filtered out during generation of report (GitHub #1149 ).
- Branches added by the Kotlin compiler version 1.5.0 and above for functions with default arguments are filtered out during generation of report (GitHub #1162 ).
- Branch added by the Kotlin compiler version 1.5.0 and above for reading from lateinit property is filtered out during generation of report (GitHub #1166 ).
- Additional bytecode generated by the Kotlin compiler version 1.5.0 and above for when expressions on kotlin.String values is filtered out during generation of report (GitHub #1172 ).
- Improved filtering of bytecode generated by Kotlin compiler versions below 1.5.0 for when expressions on kotlin.String values (GitHub #1156 ).
- Fixed parsing of SMAP generated by Kotlin compiler version 1.5.0 and above (GitHub #1164 ).
- JaCoCo now depends on ASM 9.1 (GitHub #1094 , #1097 , #1153 ).
- Maven plug-in has no dependency on maven-reporting-impl any more (GitHub #1121 ).
Release 0.8.6 (2020/09/15)
- JaCoCo now officially supports Java 14.
- Experimental support for Java 15 class files (GitHub #992 ).
- Experimental support for Java 16 class files (GitHub #1059 ).
- Methods toString , hashCode and equals generated by compiler for records are filtered out during generation of report (GitHub #990 ).
- Bridge methods are filtered out during generation of report (GitHub #1010 ).
- Methods generated by Kotlin compiler for non-overridden non-abstract methods of interfaces are filtered out during generation of report (GitHub #1012 ).
- Branches added by the Kotlin compiler version 1.3.60 for suspending functions with tail call optimization are filtered out during generation of report (GitHub #1016 ).
- Compression method of zip entries is now preserved when instrumenting archives. This allows to use JaCoCo with frameworks that expect uncompressed entries (GitHub #1018 ).
- Support for Pack200 was removed in JDK 14. JaCoCo will now throw a detailed exception when Pack200 archives are processed with the latest JDKs (GitHub #984 ).
- JaCoCo now depends on ASM 8.0.1 (GitHub #1032 , #1043 ).
API Changes
- URLStreamHandlerRuntime removed (GitHub #471 ).
Release 0.8.5 (2019/10/11)
- JaCoCo now officially supports Java 13
- Experimental support for Java 14 class files (GitHub #897 ).
- Branches added by the Kotlin compiler for open functions with default arguments are filtered out during generation of report (GitHub #887 ).
- synthetic constructors that contain values of default arguments in Kotlin should not be ignored (GitHub #888 ).
- Instrumentation should update indexes of local variables in annotations (GitHub #894 ).
- Branches added by the Kotlin compiler for functions with default arguments and containing arguments of type long or double should be filtered out during generation of report (GitHub #908 ).
- synthetic methods that contain bodies of anonymous functions in Scala should not be ignored (GitHub #912 ).
- To avoid failures with invalid class files report generation now checks that source references are actually files (GitHub #941 ).
- NullPointerException during filtering (GitHub #942 , #944 ).
- JaCoCo now distributed under the terms and conditions of the Eclipse Public License Version 2.0 (GitHub #943 ).
- Prevent startup when JaCoCo runtime cannot be initialized to avoid subsequent faults (GitHub #910 ).
- JaCoCo now depends on ASM 7.2 (GitHub #947 ).
- The coverage check API and tools (Ant, Maven) now report an error, when a coverage ratio limit is configured outside the range [0,1] to avoid common configuration mistakes (GitHub #783 ).
- Unsupported class file versions are now consistently reported as exceptions by all methods of Analyzer and Instrumenter and thus also during report generation and offline instrumentation (GitHub #952 ).
Release 0.8.4 (2019/05/08)
- JaCoCo now officially supports Java 12
- Instrumentation does not add synthetic field to Java 11+ class files, however still adds synthetic method (GitHub #845 ).
- Branches added by the Kotlin compiler version 1.3.30 for suspending lambdas and functions are filtered out during generation of report (GitHub #849 ).
- Fixed incorrect update of frames caused by bug in ASM library in case of arrays with more than 7 dimensions (GitHub #839 ).
- Fixed regression, which was introduced in 0.8.3 - module-info.class should be excluded from analysis to not cause IllegalStateException (GitHub #859 ).
- Methods Instrumenter.instrument(org.objectweb.asm.ClassReader) and Analyzer.analyzeClass(org.objectweb.asm.ClassReader) were removed (GitHub #850 ).
- JaCoCo now depends on ASM 7.1 (GitHub #851 ).
Release 0.8.3 (2019/01/23)
- jacoco-maven-plugin now requires at least Maven 3.0 (GitHub #821 ).
- JaCoCo now officially supports Java 11 (GitHub #760 ).
- Experimental support for Java 13 class files (GitHub #835 ).
- Branch added by the Kotlin compiler for "unsafe" cast operator is filtered out during generation of report (GitHub #761 ).
- Branch added by the Kotlin compiler for not-null assertion operator is filtered out during generation of report (GitHub #815 ).
- Instructions inlined by Kotlin compiler are filtered out during generation of report (GitHub #764 ).
- Branches added by the Kotlin compiler for suspending lambdas and functions are filtered out during generation of report (GitHub #802 , #803 , #809 ).
- Classes and methods annotated by annotation whose retention policy is runtime or class and whose simple name contains "Generated" (previously equality was required) are filtered out during generation of report (GitHub #822 ).
- HTML report shows message when source file can't be found (GitHub #801 ).
- HTML report shows message when class has no debug information (GitHub #818 ).
- HTML report shows message when analyzed class does not match executed (GitHub #819 ).
- HTML report shows message when no class files specified and when none of the analyzed classes contain code relevant for code coverage (GitHub #833 ).
- Empty class and sourcefile nodes are preserved and available in XML report (GitHub #817 ).
- Agent avoids conflicts with other agents when running on Java 9+ (GitHub #829 ).
- synthetic methods that contain values of default arguments in Kotlin should not be ignored (GitHub #774 ).
- synthetic methods that represent suspend functions in Kotlin should not be ignored (GitHub #804 ).
- Removed misleading parameters includes and excludes from dump , merge and restore-instrumented-classes goals of jacoco-maven-plugin, because they have no effect (GitHub #827 ).
- JaCoCo now depends on ASM 7.0 (GitHub #760 ).
Release 0.8.2 (2018/08/21)
- Experimental support for Java 11 and Java 12 class files, including JEP 12 "preview features" (GitHub #719 , #738 , #743 ).
- Branches and instructions generated by javac 11 for try-with-resources statement are filtered out (GitHub #669 ).
- Synthetic classes are filtered out during generation of report (GitHub #668 ).
- Part of bytecode generated by ECJ for switch statements on java.lang.String values is filtered out during generation of report (GitHub #735 , #741 , #746 ).
- Methods added by the Kotlin compiler that do not have line numbers are filtered out during generation of report. Idea and implementation by Nikolay Krasko (GitHub #689 ).
- Branch added by the Kotlin compiler for reading from lateinit property is filtered out during generation of report. Implementation by Fabian Mastenbroek (GitHub #707 ).
- Bytecode generated by Kotlin compiler for implicit else of when expressions that list all cases of enum or sealed class is filtered out during generation of report (GitHub #721 , #729 , #749 ).
- Additional bytecode generated by Kotlin compiler for when expressions on kotlin.String values is filtered out during generation of report (GitHub #737 , #746 ).
- Classes and methods annotated with annotation whose retention policy is runtime or class and whose simple name is Generated are filtered out during generation of report (GitHub #731 ).
- Maven goal report-aggregate now also considers dependencies specified using version range. Idea and implementation by Lukas Krejc (GitHub #658 ).
- Don't insert stackmap frames into class files with version < 1.6, this fixes regression which was introduced in version 0.6.5 (GitHub #667 ).
- Question mark in filter expressions now correctly matches exactly one character (GitHub #672 ).
- Part of bytecode that javac generates for switch statement on java.lang.String values with a small number cases is now correctly filtered out during generation of report (GitHub #730 ).
- JaCoCo now depends on ASM 6.2.1 (GitHub #706 , #725 ).
- Improved error message when already instrumented classes are used for instrumentation or analysis (GitHub #703 ).
- JaCoCo build now requires at least Maven 3.3.9 and JDK 8 (GitHub #711 ).
- The XML report now has an optional attribute sourcefilename on the class element to allow unambiguously relate classes to source files. The JaCoCo DTD version has been updated to 1.1 (GitHub #702 ).
Release 0.8.1 (2018/03/21)
- JaCoCo now supports Java 10 (GitHub #629 ).
- Empty constructor without parameters in enum is filtered out during generation of report (GitHub #649 ).
Release 0.8.0 (2018/01/02)
- JaCoCo now officially supports Java 9 (GitHub #600 ).
- JaCoCo now comes with a simple command line interface (GitHub #525 ).
- Limit configuration of Maven check goal and Ant check element now also supports percentage values (GitHub #534 ).
- Manifests of JAR files now have Automatic-Module-Name for Java 9 (GitHub #565 ).
- Maven aggregated reports will now also include modules of runtime and provided dependencies (GitHub #498 , #572 ).
During creation of reports various compiler generated artifacts are filtered out, which otherwise require unnecessary and sometimes impossible tricks to not have partial or missed coverage:
- Methods valueOf and values of enum types (GitHub #491 ).
- Private empty no-argument constructors (GitHub #529 ).
- Methods annotated with @lombok.Generated to better integrate with Lombok >= 1.16.14. Initial analysis and contribution by Rüdiger zu Dohna (GitHub #513 ).
- Methods annotated with @groovy.transform.Generated to better integrate with Groovy >= 2.5.0. Thanks to Andres Almiray for adding the annotation to Groovy (GitHub #610 ).
- Part of bytecode for synchronized blocks (GitHub #501 ).
- Part of bytecode for try-with-resources statements (GitHub #500 ).
- Part of bytecode for finally blocks (GitHub #604 ).
- Part of bytecode for switch statements on java.lang.String values (GitHub #596 ).
Note: Tools that directly read exec files and embed JaCoCo for this (such as SonarQube or Jenkins) will provide filtering functionality only after they updated to this version of JaCoCo.
- Fixed bug in instrumentation of exception handlers, which was causing damage of structured locking in certain situations and as consequence poor performance of instrumented methods, analysis and fix contributed by Allen Hair (GitHub #627 ).
- dump commands now report error when server unexpectedly closes connection without sending response (GitHub #538 ).
- Reduced chance of conflict with other agents (GitHub #555 ).
- Restored Maven help goal that was missing in version 0.7.9 (GitHub #559 ).
- NullPointerException during offline instrumentation of module-info.class (GitHub #600 , GitHub #634 ).
- Incorrect update of frames caused by bug in ASM library (GitHub #600 ).
- Loss of InnerClasses attribute caused by bug in ASM library (GitHub #600 ).
- NegativeArraySizeException during instrumentation caused by bug in ASM library (GitHub #600 ).
- JaCoCo now depends on ASM 6.0 (GitHub #600 ).
- More information about context is provided when unable to read input during instrumentation (GitHub #527 ).
- More information about context is provided when unable to read stream during analysis (GitHub #541 ).
Release 0.7.9 (2017/02/05)
- " java.lang.ClassFormatError: Short length on BootstrapMethods in class file " caused by bug in ASM library (GitHub #462 ).
- Do not recompute frames in case of large methods, otherwise java.lang.ClassNotFoundException might be thrown (GitHub #177 ).
- ExecutionDataWriter.FORMAT_VERSION is not a compile-time constant (GitHub #474 ).
- Maven goal "prepare-agent" should not overwrite existing property value if execution was skipped (GitHub #486 ).
- JaCoCo.ASM_API_VERSION removed (GitHub #474 ).
- JaCoCo now depends on ASM 5.2.
- OSGi metadata now generated automatically and additionally include uses directives, Require-Capability attribute, and export of all internal packages with x-internal:=true directive (GitHub #211 ).
- Removed OSGi attributes that were mistakenly added in version 0.6.1 into jacocoant.jar that contains all dependencies (GitHub #211 ).
Release 0.7.8 (2016/12/09)
- User property jacoco.dataFile for parameter dataFile of Maven report goal (GitHub #322 ).
- Use RoundingMode#FLOOR instead of RoundingMode#HALF_EVEN for percentages in HTML report, so that "99.5" is displayed as "99%", not as "100%" (GitHub #452 ).
- Do not add useless members into Java 8 interfaces that have only interface initialization and abstract methods (GitHub #441 ).
- Fix instrumentation to not violate Java Virtual Machine Specification regarding initialization of final fields, otherwise IllegalAccessError will be thrown starting from OpenJDK 9 EA b127 (GitHub #434 ).
- Fix instrumentation of interfaces with default methods to not create incorrect constant pool entries, which lead to IncompatibleClassChangeError starting from OpenJDK 9 EA b122 (GitHub #428 ).
- Add Maven goal report-aggregate to lifecycle-mapping-metadata.xml (GitHub #427 ).
- Released JaCoCo JARs are not signed any more. Signed versions of JaCoCo are now available from the Eclipse Orbit project (GitHub #466 ).
- Simplified numbering of versions - JaCoCo JARs in Maven Central repository do not have qualifier any more (GitHub #468 ).
Release 0.7.7 (2016/06/06)
- New Maven goal report-aggregate to create reports for multi-module projects (GitHub #388 ).
- New parameters title and footer for Maven reporting goals allow customization of generated reports.
- Renamed "dot" resources in generated HTML reports to become more web hosting friendly (GitHub #401 ).
- Experimental support for Java 9 class files (GitHub #406 ).
- Don't suppress EOF errors in case of truncated execution data files (GitHub #397 ).
- JaCoCo now depends on ASM 5.1.
- Empty probe arrays are not written to execution data files any more. This reduces exec file size significantly for per-test data dumps. (GitHub #387 ).
- More information about context is provided when unable to read input during analysis. (GitHub #400 ).
- Require at least Maven 3.0 for build of JaCoCo.
Release 0.7.6 (2016/02/18)
- New agent option inclnolocationclasses to support execution environments like Android where no source location is provided with classes (GitHub #288 ).
- Improved error message in case of incompatible execution data files. (GitHub #319 ).
- Command line agent options now supports comma in file names. Contributed by Jochen Berger. (GitHub #358 ).
- Fix MBeanClient example (GitHub #333 ).
- Avoid ConcurrentModificationException during shutdown (GitHub #364 ).
- In case of incompatible execution data formats read from another JaCoCo version ExecutionDataReader.read() now throws a IncompatibleExecDataVersionException .
- JaCoCo now depends on ASM 5.0.4.
Release 0.7.5 (2015/05/24)
- Better detection of coverage in code blocks with implicit exceptions. (GitHub #310 ).
- Added lifecycle-mapping-metadata.xml for M2E (GitHub #203 ).
- Allow locales with country and variant for Ant report task (GitHub #289 ).
- For the Ant tasks coverage and agent the destfile attribute is now passed as an absolute path also in the default case (GitHub #301 ).
- The exec file version has been updated and is not compatible with previous versions.
Release 0.7.4 (2015/02/26)
- Restored exec file compatibility with version 0.7.2 by fixing missing probes in case of try/catch blocks which are jump targets. (GitHub #286 ).
Release 0.7.3 (2015/02/19)
- For offline instrumemtation agent configuration supports system properties replacements. Implementation based on pull request of GitHub user 'debugger' (GitHub #262 ).
- Exclude dynamically generated classes from instrumentation for better interoperability with JMockit, analysis contributed by Rogério Liesenfeld (GitHub #272 ).
- Instrumented bytecode now compatible with Android ART runtime, analysis and fix contributed by Allen Hair (GitHub #265 ).
Release 0.7.2 (2014/09/12)
- Do not ignore synthetic lambda methods to get code coverage for Java 8 lambda expressions (GitHub #232 ).
- New configuration option for the JaCoCo agent inclbootstrapclasses to also instrument classes from the bootstrap class loader (GitHub #49 ).
- Agent uses unique file names to dump class files (GitHub #225 ).
Release 0.7.1 (2014/05/08)
- Fixed failure with default methods in Java 8 interfaces (GitHub #201 ).
- Better interoperability with JMockit, analysis and fix contributed by Rogério Liesenfeld (GitHub #35 and #54 ).
- JaCoCo now depends on ASM 5.0.1 (GitHub #201 ).
Release 0.7.0 (2014/03/18)
- JaCoCo now supports Java 8 (GitHub #74 ).
- JaCoCo now depends on ASM 5.0 using asm-debug-all instead of asm-all (GitHub #199 ).
Release 0.6.5 (2014/03/03)
- Warnings are logged during report generation if different versions of classes are used than at runtime (GitHub #185 ).
- Signatures are removed from instrumented JAR files (GitHub #186 ).
- Skip jacoco instrumentation for mvn modules with package type ear (GitHub #169 ).
- Align skip conditions and messages for Maven goals and give reasons. This includes removal of the specific skip condition for packages e.g. POMs and instead checks existence of target/classes in appropriate goals (GitHub #171 ).
- GitHub #44: (Regression) Agent Mojo should set empty property, if execution was skipped (GitHub #192 ).
- Restrict visibility of methods in abstract classes of jacoco-maven-plugin (GitHub #175 ).
Release 0.6.4 (2013/12/10)
- Support for Android Strict Mode (GitHub #113 ).
- New dump Mojo for Maven plug-in (GitHub #107 ).
- New merge Mojo for Maven plug-in, contributed by Mads Mohr Christensen (GitHub #126 ).
- Additional list of source files for every package in HTML report (GitHub #142 ).
- Additional report-integration and prepare-agent-integration goals for integration tests. (GitHub #152 , #161 ).
- Multiple executions of Maven goal "prepare-agent" should not lead to incorrect configuration (GitHub #40 ).
- Avoid direct dependency on java.lang.management APIs to allow usage on Android (GitHub #150 ).
- All JaCoCo Maven goals are marked as thread-safe (GitHub #133 ).
- check and merge goal failures in jacoco-maven-plugin with Maven 2.2.1 due to incompatible configuration (GitHub #129 ).
- New API package org.jacoco.core.tools for shared high-level tools. (GitHub #159 ).
Release 0.6.3 (2013/06/03)
- Support for archives in Pack200 format (GitHub #91 ).
- The coverage check has been reworked to allow checks on all counter values on all element types (GitHub #106 ).
- Coverage checks are now also available in Ant (GitHub #106 ).
- Fixed inconsistent stackmap frames when instrumenting class files produced by certain tools like ProGuard (GitHub #85 ).
- More context information when exceptions occur during analysis or instrumentation (GitHub #104 ).
- If analysis is performed on offline instrumented classes - which is an build configuration error - an exception is now thrown (GitHub #108 ).
- The configuration of the Maven check goal has been reworked to support checks on any element type (GitHub #106 ).
- Analyzer and Instrumenter expect resource name as additional parameter for better error messages (GitHub #104 ).
Release 0.6.2 (2013/02/03)
- Support for offline instrumentation (GitHub #4 , #64 ).
- JaCoCo agent exposes runtime API for direct integration with application under test (GitHub #61 ).
- Support for parallel test execution: Different agents can now safely write to the same *.exec file (GitHub #52 ).
- New output mode 'none' can be used when agent is only controlled via JMX or its new runtime API (GitHub #63 ).
- Better error message in case of invalid stackmap frames (GitHub #73 ).
- jacoco-maven-plugin: default phase for goal "report" - "verify" (GitHub #72 ).
- For every build the corresponding Git commit hash is included as Eclipse-SourceReferences manifest headers (GitHub #7 , #59 ).
- Adjust saturation of red source highlighting in HTML reports to make JaCoCo reports more accessible to red/green blind users.
- The output mode mbean of the agent has been dropped in favor of the new boolean option jmx . This allows to combine JMX access with any other output mode (GitHub #62 ).
Release 0.6.1 (2012/12/23)
- Add a coverage check Mojo, contributed by Kyle Lieber (GitHub #6 ).
- jacocoant.jar should not conflict with ASM 3.x (GitHub #39 ).
- Agent Mojo should set empty property, if execution was skipped (GitHub #44 ).
- Upgrade to ASM 4.1 (GitHub #37 ).
- Log location of merged execution data file in Ant merge task (GitHub #29 ).
Release 0.6.0 (2012/10/06)
- Full support for Java 7 including INVOKEDYNAMIC as JaCoCo is now based on ASM 4.0 (GitHub #5 ).
- Maven plugin should skip creation of report if the execution data file is missing. This avoids appearance of stack traces in case when JVM was not forked, e.g. if there are no tests to run (SF #3563431, GitHub #19 ).
- Maven plugin should fail if unable to read execution data file or create report (GitHub #19 ).
- Only colon as separator character supported in agent parameters. The deprecated pipe character is no longer supported.
Release 0.5.10 (2012/08/31)
- Correct stackmap frames for new long[] arrays (SF #3553210).
- Properly resolve the fork variable for tasks wrapped by the coverage Ant task (Trac #213).
- Source tree has been migrated to Git and is now hosted on Github at https://github.com/jacoco/jacoco .
Release 0.5.9 (2012/07/30)
- Don't produce invalid class files in case of unexpected stackmap frames (SF #3543758).
Release 0.5.8 (2012/07/11)
- Support for parallel Maven builds (Trac #191).
- New agent option classdumpdir to dump all class files seen by the JaCoCo agent to disk. This option is also available for Ant and Maven (Trac #208).
- Allow instrumentation of classes with dead code (SF #3538112).
- Reworked instrumentation strategy to avoid verifier error "Uninitialized object exists on backward branch" with certain Java 7 class files (Trac #154).
- Documentation now includes Maven example and Maven goal documentation (Trac #201, #202).
Release 0.5.7 (2012/04/19)
- Support for class redefinitions by other agents like JMockit (SF #3509409).
- Remove class file attributes with invalid code offsets caused by other byte code processing tools to avoid verifier errors (Trac #196).
- Improved logging for Ant tasks (SF #3518429).
- In case of failures the agent should log the original exception.
Release 0.5.6 (2012/01/23)
- jacoco-maven-plugin can be used together with maven-site-plugin (Trac #181).
- The report Ant task now also supports directory resources to specify source folders. This allows reading source files from multiple directories. Contributed by Dominik Stadler (Trac #119).
- Don't insert stackmap frames for class files before version 1.6.
- Regression, which was introduced in 0.5.4 - restored compatibility of jacoco-maven-plugin with Maven 2 (Trac #182).
Release 0.5.5 (2011/12/15)
- Correct default value for the append property of the dump Ant task is true (Trac #178).
- Try/catch blocks must not be counted as instructions (Trac #179).
- Upgrade to ASM 3.3.1.
Release 0.5.4 (2011/11/11)
- Maven plug-in: respect includes and excludes properties in report Mojo (Trac #160). Also note that: <configuration> <includes>org.foo.*:org.bar.*</includes> <excludes>com.foo.*:com.bar.*</excludes> </configuration> must be replaced on: <configuration> <includes> <include>org.foo.*</include> <include>org.bar.*</include> </includes> <excludes> <exclude>com.foo.*</exclude> <exclude>com.bar.*</exclude> </excludes> </configuration>
- Instrumenter now only requires IExecutionDataAccessorGenerator instead of IRuntime (Trac #174).
- Removed reference to internal implementation classes from CoverageBuilder API.
- Release bundles from now on signed again.
- Several documentation updates.
Release 0.5.3 (2011/07/06)
- New Maven plug-in for JaCoCo agent setup and basic reporting (Trac #25).
- Additional output mode implementation for JaCoCo agent based on JMX.
- Fixed problem with reporting of nested group structures (Trac #157).
- JaCoCo build based on Maven (Trac #136).
- JaCoCo published to Maven repository (Trac #149).
Release 0.5.2 (2011/05/19)
- JaCoCo reports cyclomatic complexity numbers (Trac #129).
- For HTML reports the tab width can be specified on the sourcefiles attribute of the report Ant task (Track #152).
- Removed duplicate counters in the root node of XML reports (Trac #155).
- Avoid StackOverflowException when analyzing methods with very long instruction sequences (Trac #156). Many thanks to Jean-Eric Cuendet for reporting and analyzing this!
- ICoverageNode API has been extended for cyclomatic complexity (Trac #129).
- XML and CSV report includes new counter type COMPLEXITY (Trac #129).
- New method getTabWidth() in callback interface ISourceFileLocator instead of HTMLReportFormatter.setTabWidth() which has been removed. (Trac #152).
Release 0.5.1 (2011/03/21)
- Duplicate classes with identical identifiers are now ignored during analysis.
- Added support for TestNG to Ant task Coverage (Track #144).
- Calculate correct stackmap frames for Java 1.6 branches (Trac #139).
- Link source files also for classes in default package (Trac #151).
- API documentation cleanup (Track #140).
- Removed obsolete examples from documentation (Trac #141).
- Added reporting API example (Trac #146).
- Reduced file size of HTML report source pages (Trac #148).
- Simplified reporting API (Trac #53).
- Use colon as separator character in agent parameters (Trac #143).
- Now also empty files are accepted as *.exec files (Trac #150).
Release 0.5.0 (2011/01/19)
- JaCoCo now reports branch coverage (Track #66).
- Only process actual Java class files during analysis (SF #3106102).
- Fix broken source links due to sort hash (Track #125).
- Fixed invalid OSGi headers in MANIFEST.MF files (Track #127).
- Try to avoid interference with Hibernate (SF #3134190).
- Provide proper error message in case of duplicate class names in the same group (SF #3110219).
- Allow any number of probes in static interface initializers (SF #3161106).
- All analysis specific APIs have been moved to package org.jacoco.core.analysis .
- The IStructureVisitor interface has been replaced by a simplified version called ICoverageVisitor (Track #132).
- All counter creation and update APIs now accept missed items and covered items as parameters (Track #131).
- Instructions are now counted on a per line basis. Therefore some interfaces in the org.jacoco.core.analysis package have changed as well as the line element in the XML report (Track #130).
- Several internal implementation classes have removed from the core APIs or have been replaced by new interfaces (Track #133).
Release 0.4.1 (2010/10/07)
- New attribute line for method elements in the XML report containing the first source line number of the method. (Track #120).
- Optional locale attribute for number rendering HTML reports, also available as an attribute of the html tag of the report Ant task (Track #122).
- Coverage tables in HTML report are now sortable (Track #98).
- The report Ant task issues a warning if source files are provided but class files do not contain debug information to collect line numbers (SF #3024486).
- Reduced memory footprint for coverage data by 30% (Track #106).
- Moved to Eclipse 3.6.x as development environment (Trac #115).
- All delivered bundles and JAR files are signed (Trac #118).
- Better error message when multiple JaCoCo agents are specified (Track #103).
- Fixed potential NPE at shutdown when running agent in tcpserver mode (Track #117).
- Agent now fails at startup when execution data file can't be opened (Track #121).
Release 0.4.0 (2010/06/04)
- Execution data now includes session information: an arbitrary identifier, the start time and dump time (Trac #88).
- Added session information to XML report (Trac #92).
- New "Sessions" page in the HTML report shows information about each sessions wherein execution data has been collected for the report (Trac #93). Additionally all classes with execution data available are listed on this page (Trac #94).
- The agent now supports remote dumps via TCP/IP connections (Trac #82).
- New Ant task dump to remotely collect coverage data from agents (Trac #100).
- Execution data file header is written and read in any case (Trac #72).
- Added dumponexit to agent options (Trac #82).
- Added sessionid to agent options (Trac #88).
- Added output, address and port to agent options (Trac #82).
- Additional and modified methods in IRuntime to produce session information (Trac #88).
- Coverage element type SESSION removed (Trac #95).
- Removed several internal APIs from package org.jacoco.core.instr used for class instrumentation.
- Renamed class org.jacoco.report.csv.CsvFormatter to CSVFormatter (upper case) for consistency with other formatters.
Release 0.3.3 (2010/04/19)
- Support for different archives (jar, war, ear etc.) and nested archives (Trac #78).
- XML report with line level coverage information (requested for Sonar).
- Correct stackmap frames for Java 1.6 class files. (Track #81).
- Avoid usage of LocalVariableSorter due to ASM bug #314563 (Track #69).
- Nested Java/JUnit Ant tasks not being executed when coverage task disabled. (Track #85).
Release 0.3.2 (2010/04/01)
- New HTML report option to directly create a zip file containing the report (Trac #12).
- Code coverage for static initializers in interfaces (Trac #21).
- Better error handling for report Ant task (Trac #71).
- Classes without instructions are excluded from reports (Trac #73).
- XML and CSV report output now also works for structures without groups (Track #76).
- Consistent usage of the term "Missed" instead of "NotCovered" in all APIs (Trac #72).
- To support "off-line" instrumentation scenarios it is not required any more to register instrumented classes with the runtime (Trac #74).
Release 0.3.1 (2010/02/09)
- Ant tasks broken on Linux (Trac #68).
Release 0.3.0 (2010/02/02)
- Report renders anonymous classes with type information (Trac #46).
- enabled property added to agent and coverage Ant tasks (Trac #63).
- Ant task merge added (Trac #52).
- New IRuntime implementation enables JaCoCo usage for J2EE application servers like Glassfish.
- Agent option and Ant task parameter file changed to destfile (Trac #59).
- Agent option and Ant task parameter merge changed to append (Trac #51).
Release 0.2.0 (2010/01/08)
- Simplified probe data structure reduces memory usage (Trac #47).
- Performance test becomes part of the build.
- New bundle org.jacoco.agent that provides the Java agent as a resource (Trac #50).
- ArrayIndexOutOfBoundsException due to inconsistent processing while instrumentation and analysis (Trac #44).
Release 0.1.0 (2009/10/28)
The very first JaCoCo release.
Jacoco code coverage issue
Hi team, When I’m trying to run the maven project using jacoco plugin to check the code coverage results I am facing huge issue. When I am trying to run in my local environment using jacoco few test cases aren’t showing coverage results and getting the below error.
[INFO] — jacoco-maven-plugin:0.7.6.201602180812:report (post-unit-test) @ kcam — [INFO] Analyzed bundle ‘KCAM :: 1.1.1-SNAPSHOT’ with 79 classes [WARNING] Classes in bundle ‘KCAM :: 1.1.1-SNAPSHOT’ do no match with execution data. For report generation the same class files must be used as at runtime. [WARNING] Execution data for class XXXXXXXX does not match. [WARNING] Execution data for class XXXXXXXX does not match. [WARNING] Execution data for class XXXXXXXX does not match. [WARNING] Execution data for class XXXXXXXX does not match.[
Here is the jacoco related plugin details in my pom.xml
let me know what is the cause of getting zero coverage using jacoco plugin
Are you running the tests/generating the report with the same class files and in the same location that you’re running analysis from?
Yes ann.running with same lass files in the same location
I Googled the error message that’s repeated & got this SO answer. Which led me to this one about the first error in your log . It seems that something changes during your build/test/analyze process.

JaCoCo comes with Ant tasks to launch Java programs with execution recording and for creating coverage reports from the recorded data. Execution data can be collected and managed with the tasks coverage , agent , dump and merge . Reports in different formats are created with the report task. For offline instrumentation the task instrument can be used to prepare class files.
If you want to have line number information included in the coverage reports or you want source code highlighting the class files of the test target must be compiled with debug information.
The JaCoCo distribution contains a simple example how code coverage can be added to a Ant based build. The build script compiles Java sources, runs an simple Java program and creates a coverage report. The complete example is located in the ./doc/examples/build folder of the distribution.
Prerequisites
The JaCoCo Ant tasks require
- Ant 1.7.0 or higher and
- Java 1.5 or higher (for both, the Ant runner and the test executor).
All tasks are defined in jacocoant.jar (which is part of the distribution) and can be included in your Ant scripts with the usual taskdef declaration:
Alternatively you might also place the jacocoant.jar in your Ant ANT_HOME /lib folder. If you use the name space URI antlib:org.jacoco.ant for JaCoCo tasks Ant will find them automatically without the taskdef declaration above.
Declaring a XML namespace for JaCoCo tasks is optional but always recommended if you mix tasks from different libraries. All subsequent examples use the jacoco prefix declared above. If you don't declare a separate namespace the jacoco prefix must be removed from the following examples.
Task coverage
The standard Ant tasks to launch Java programs are java , junit and testng . To add code coverage recording to these tasks they can simply be wrapped with the coverage task as shown in the following examples:
Resulting coverage information is collected during execution and written to a file when the process terminates. Note the fork attribute above in the wrapped java task.
The nested task always has to declare fork="true" , otherwise the coverage task can't record coverage information and will fail. In addition the junit task should declare forkmode="once" to avoid starting a new JVM for every single test case and decreasing execution performance dramatically (unless this is required by the nature of the test cases). Note that forkmode="perTest" or forkmode="perBatch" should not be combined with append="false" as the execution data file is overwritten with the execution of every test.
The coverage task must wrap exactly one task. While it typically works without any configuration, the behavior can be adjusted with some optional attributes:
If the coverage task is not suitable for your launch target, you might alternatively use the agent task to create the Java agent parameter. The following example defines a Ant property with the name agentvmparam that can be directly used as a Java VM parameter:
This task has the same attributes as the coverage task plus an additional property to specify the target property name:
This task allows to remotely collect execution data from another JVM without stopping it. For example:
Remote dumps are usefull for long running Java processes like application servers.
The target JVM needs to have a JaCoCo agent configured with output mode tcpserver . See coverage and agent tasks above.
The dump task has the following attributes:
This task can be used to merge the execution data from multiple test runs into a single data store.
The task definition can contain any number of resource collection types and has the following mandatory attribute:
Task report
Finally different reports can be created with the report task. A report task declaration consists of different sections, two specify the input data, additional ones specify the output formats:
As you can see from the example above the report task is based on several nested elements:
Element executiondata
Within this element Ant resources and resource collections can be specified, that represent JaCoCo execution data files. If more than one execution data file is specified, execution data is combined. A particular piece of code is considered executed when it is marked as such in any of the input files.
Element structure
This element defines the report structure. It might contain the following nested elements:
- classfiles : Container element for Ant resources and resource collections that can specify Java class files, archive files (jar, war, ear etc. or Pack200) or folders containing class files. Archives and folders are searched recursively for class files.
- sourcefiles : Optional container element for Ant resources and resource collections that specify corresponding source files. If source files are specified, some report formats include highlighted source code. Source files can be specified as individual files or as source directories.
The sourcefiles element has these optional attributes:
Important: Source file resources must always be specified relative to the respective source folder. If directory resources are given, they must directly point to source folders. Otherwise source lookup will not succeed.
Note that the classfiles and sourcefiles elements accept any Ant resource collection . Therefore also filtering the class file set is possible and allows to narrow the scope of the report, for example:
Performance Warning: Although it is technically possible and sometimes convenient to use Ant's zipfileset to specify class or source files, this resource type has poor performance characteristics and comes with an huge memory overhead especially for large scale projects.
The structure can be refined with a hierarchy of group elements. This way the coverage report can reflect different modules of a software project. For each group element the corresponding class and source files can be specified separately. For example:
Both structure and group elements have the following mandatory attribute:
Element html
Create a multi-page report in HTML format. The report can either be written as multiple files into a directory or compressed into a single ZIP file.
Element xml
Create a single-file report in XML format.
Element csv
Create single-file report in CSV format.
Element check
This report type does not actually create a report. It checks coverage counters and reports violations of configured rules. Every rule is applied to elements of a given type (class, package, bundle, etc.) and has a list of limits which are checked for every element. The following example checks that for every package the line coverage is at least 80% and no class is missed:
The check element has the following attributes:
Within the check element any number of rule elements can be nested:
Within the rule element any number of limit elements can be nested:
Task instrument
Warning: The preferred way for code coverage analysis with JaCoCo is on-the-fly instrumentation. Offline instrumentation has several drawbacks and should only be used if a specific scenario explicitly requires this mode. Please consult documentation about offline instrumentation before using this mode.
This task is used for offline instrumentation of class files. The task takes a set of files and writes instrumented versions to a specified location. The task takes any file type as input. Java class files are instrumented. Archives (jar, war, ear etc. or Pack200) are searched recursively for class files which then get instrumented. All other files are copied without modification.
- Python »
- 3.12.0 Documentation »
- The Python Tutorial »
- Theme Auto Light Dark |
9. Classes ¶
Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made. Each class instance can have attributes attached to it for maintaining its state. Class instances can also have methods (defined by its class) for modifying its state.
Compared with other programming languages, Python’s class mechanism adds classes with a minimum of new syntax and semantics. It is a mixture of the class mechanisms found in C++ and Modula-3. Python classes provide all the standard features of Object Oriented Programming: the class inheritance mechanism allows multiple base classes, a derived class can override any methods of its base class or classes, and a method can call the method of a base class with the same name. Objects can contain arbitrary amounts and kinds of data. As is true for modules, classes partake of the dynamic nature of Python: they are created at runtime, and can be modified further after creation.
In C++ terminology, normally class members (including the data members) are public (except see below Private Variables ), and all member functions are virtual . As in Modula-3, there are no shorthands for referencing the object’s members from its methods: the method function is declared with an explicit first argument representing the object, which is provided implicitly by the call. As in Smalltalk, classes themselves are objects. This provides semantics for importing and renaming. Unlike C++ and Modula-3, built-in types can be used as base classes for extension by the user. Also, like in C++, most built-in operators with special syntax (arithmetic operators, subscripting etc.) can be redefined for class instances.
(Lacking universally accepted terminology to talk about classes, I will make occasional use of Smalltalk and C++ terms. I would use Modula-3 terms, since its object-oriented semantics are closer to those of Python than C++, but I expect that few readers have heard of it.)
9.1. A Word About Names and Objects ¶
Objects have individuality, and multiple names (in multiple scopes) can be bound to the same object. This is known as aliasing in other languages. This is usually not appreciated on a first glance at Python, and can be safely ignored when dealing with immutable basic types (numbers, strings, tuples). However, aliasing has a possibly surprising effect on the semantics of Python code involving mutable objects such as lists, dictionaries, and most other types. This is usually used to the benefit of the program, since aliases behave like pointers in some respects. For example, passing an object is cheap since only a pointer is passed by the implementation; and if a function modifies an object passed as an argument, the caller will see the change — this eliminates the need for two different argument passing mechanisms as in Pascal.
9.2. Python Scopes and Namespaces ¶
Before introducing classes, I first have to tell you something about Python’s scope rules. Class definitions play some neat tricks with namespaces, and you need to know how scopes and namespaces work to fully understand what’s going on. Incidentally, knowledge about this subject is useful for any advanced Python programmer.
Let’s begin with some definitions.
A namespace is a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries, but that’s normally not noticeable in any way (except for performance), and it may change in the future. Examples of namespaces are: the set of built-in names (containing functions such as abs() , and built-in exception names); the global names in a module; and the local names in a function invocation. In a sense the set of attributes of an object also form a namespace. The important thing to know about namespaces is that there is absolutely no relation between names in different namespaces; for instance, two different modules may both define a function maximize without confusion — users of the modules must prefix it with the module name.
By the way, I use the word attribute for any name following a dot — for example, in the expression z.real , real is an attribute of the object z . Strictly speaking, references to names in modules are attribute references: in the expression modname.funcname , modname is a module object and funcname is an attribute of it. In this case there happens to be a straightforward mapping between the module’s attributes and the global names defined in the module: they share the same namespace! 1
Attributes may be read-only or writable. In the latter case, assignment to attributes is possible. Module attributes are writable: you can write modname.the_answer = 42 . Writable attributes may also be deleted with the del statement. For example, del modname.the_answer will remove the attribute the_answer from the object named by modname .
Namespaces are created at different moments and have different lifetimes. The namespace containing the built-in names is created when the Python interpreter starts up, and is never deleted. The global namespace for a module is created when the module definition is read in; normally, module namespaces also last until the interpreter quits. The statements executed by the top-level invocation of the interpreter, either read from a script file or interactively, are considered part of a module called __main__ , so they have their own global namespace. (The built-in names actually also live in a module; this is called builtins .)
The local namespace for a function is created when the function is called, and deleted when the function returns or raises an exception that is not handled within the function. (Actually, forgetting would be a better way to describe what actually happens.) Of course, recursive invocations each have their own local namespace.
A scope is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means that an unqualified reference to a name attempts to find the name in the namespace.
Although scopes are determined statically, they are used dynamically. At any time during execution, there are 3 or 4 nested scopes whose namespaces are directly accessible:
the innermost scope, which is searched first, contains the local names
the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contain non-local, but also non-global names
the next-to-last scope contains the current module’s global names
the outermost scope (searched last) is the namespace containing built-in names
If a name is declared global, then all references and assignments go directly to the next-to-last scope containing the module’s global names. To rebind variables found outside of the innermost scope, the nonlocal statement can be used; if not declared nonlocal, those variables are read-only (an attempt to write to such a variable will simply create a new local variable in the innermost scope, leaving the identically named outer variable unchanged).
Usually, the local scope references the local names of the (textually) current function. Outside functions, the local scope references the same namespace as the global scope: the module’s namespace. Class definitions place yet another namespace in the local scope.
It is important to realize that scopes are determined textually: the global scope of a function defined in a module is that module’s namespace, no matter from where or by what alias the function is called. On the other hand, the actual search for names is done dynamically, at run time — however, the language definition is evolving towards static name resolution, at “compile” time, so don’t rely on dynamic name resolution! (In fact, local variables are already determined statically.)
A special quirk of Python is that – if no global or nonlocal statement is in effect – assignments to names always go into the innermost scope. Assignments do not copy data — they just bind names to objects. The same is true for deletions: the statement del x removes the binding of x from the namespace referenced by the local scope. In fact, all operations that introduce new names use the local scope: in particular, import statements and function definitions bind the module or function name in the local scope.
The global statement can be used to indicate that particular variables live in the global scope and should be rebound there; the nonlocal statement indicates that particular variables live in an enclosing scope and should be rebound there.

9.2.1. Scopes and Namespaces Example ¶
This is an example demonstrating how to reference the different scopes and namespaces, and how global and nonlocal affect variable binding:
The output of the example code is:
Note how the local assignment (which is default) didn’t change scope_test 's binding of spam . The nonlocal assignment changed scope_test 's binding of spam , and the global assignment changed the module-level binding.
You can also see that there was no previous binding for spam before the global assignment.
9.3. A First Look at Classes ¶
Classes introduce a little bit of new syntax, three new object types, and some new semantics.
9.3.1. Class Definition Syntax ¶
The simplest form of class definition looks like this:
Class definitions, like function definitions ( def statements) must be executed before they have any effect. (You could conceivably place a class definition in a branch of an if statement, or inside a function.)
In practice, the statements inside a class definition will usually be function definitions, but other statements are allowed, and sometimes useful — we’ll come back to this later. The function definitions inside a class normally have a peculiar form of argument list, dictated by the calling conventions for methods — again, this is explained later.
When a class definition is entered, a new namespace is created, and used as the local scope — thus, all assignments to local variables go into this new namespace. In particular, function definitions bind the name of the new function here.
When a class definition is left normally (via the end), a class object is created. This is basically a wrapper around the contents of the namespace created by the class definition; we’ll learn more about class objects in the next section. The original local scope (the one in effect just before the class definition was entered) is reinstated, and the class object is bound here to the class name given in the class definition header ( ClassName in the example).
9.3.2. Class Objects ¶
Class objects support two kinds of operations: attribute references and instantiation.
Attribute references use the standard syntax used for all attribute references in Python: obj.name . Valid attribute names are all the names that were in the class’s namespace when the class object was created. So, if the class definition looked like this:
then MyClass.i and MyClass.f are valid attribute references, returning an integer and a function object, respectively. Class attributes can also be assigned to, so you can change the value of MyClass.i by assignment. __doc__ is also a valid attribute, returning the docstring belonging to the class: "A simple example class" .
Class instantiation uses function notation. Just pretend that the class object is a parameterless function that returns a new instance of the class. For example (assuming the above class):
creates a new instance of the class and assigns this object to the local variable x .
The instantiation operation (“calling” a class object) creates an empty object. Many classes like to create objects with instances customized to a specific initial state. Therefore a class may define a special method named __init__() , like this:
When a class defines an __init__() method, class instantiation automatically invokes __init__() for the newly created class instance. So in this example, a new, initialized instance can be obtained by:
Of course, the __init__() method may have arguments for greater flexibility. In that case, arguments given to the class instantiation operator are passed on to __init__() . For example,
9.3.3. Instance Objects ¶
Now what can we do with instance objects? The only operations understood by instance objects are attribute references. There are two kinds of valid attribute names: data attributes and methods.
data attributes correspond to “instance variables” in Smalltalk, and to “data members” in C++. Data attributes need not be declared; like local variables, they spring into existence when they are first assigned to. For example, if x is the instance of MyClass created above, the following piece of code will print the value 16 , without leaving a trace:
The other kind of instance attribute reference is a method . A method is a function that “belongs to” an object. (In Python, the term method is not unique to class instances: other object types can have methods as well. For example, list objects have methods called append, insert, remove, sort, and so on. However, in the following discussion, we’ll use the term method exclusively to mean methods of class instance objects, unless explicitly stated otherwise.)
Valid method names of an instance object depend on its class. By definition, all attributes of a class that are function objects define corresponding methods of its instances. So in our example, x.f is a valid method reference, since MyClass.f is a function, but x.i is not, since MyClass.i is not. But x.f is not the same thing as MyClass.f — it is a method object , not a function object.
9.3.4. Method Objects ¶
Usually, a method is called right after it is bound:
In the MyClass example, this will return the string 'hello world' . However, it is not necessary to call a method right away: x.f is a method object, and can be stored away and called at a later time. For example:
will continue to print hello world until the end of time.
What exactly happens when a method is called? You may have noticed that x.f() was called without an argument above, even though the function definition for f() specified an argument. What happened to the argument? Surely Python raises an exception when a function that requires an argument is called without any — even if the argument isn’t actually used…
Actually, you may have guessed the answer: the special thing about methods is that the instance object is passed as the first argument of the function. In our example, the call x.f() is exactly equivalent to MyClass.f(x) . In general, calling a method with a list of n arguments is equivalent to calling the corresponding function with an argument list that is created by inserting the method’s instance object before the first argument.
If you still don’t understand how methods work, a look at the implementation can perhaps clarify matters. When a non-data attribute of an instance is referenced, the instance’s class is searched. If the name denotes a valid class attribute that is a function object, a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object. When the method object is called with an argument list, a new argument list is constructed from the instance object and the argument list, and the function object is called with this new argument list.
9.3.5. Class and Instance Variables ¶
Generally speaking, instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class:
As discussed in A Word About Names and Objects , shared data can have possibly surprising effects with involving mutable objects such as lists and dictionaries. For example, the tricks list in the following code should not be used as a class variable because just a single list would be shared by all Dog instances:
Correct design of the class should use an instance variable instead:
9.4. Random Remarks ¶
If the same attribute name occurs in both an instance and in a class, then attribute lookup prioritizes the instance:
Data attributes may be referenced by methods as well as by ordinary users (“clients”) of an object. In other words, classes are not usable to implement pure abstract data types. In fact, nothing in Python makes it possible to enforce data hiding — it is all based upon convention. (On the other hand, the Python implementation, written in C, can completely hide implementation details and control access to an object if necessary; this can be used by extensions to Python written in C.)
Clients should use data attributes with care — clients may mess up invariants maintained by the methods by stamping on their data attributes. Note that clients may add data attributes of their own to an instance object without affecting the validity of the methods, as long as name conflicts are avoided — again, a naming convention can save a lot of headaches here.
There is no shorthand for referencing data attributes (or other methods!) from within methods. I find that this actually increases the readability of methods: there is no chance of confusing local variables and instance variables when glancing through a method.
Often, the first argument of a method is called self . This is nothing more than a convention: the name self has absolutely no special meaning to Python. Note, however, that by not following the convention your code may be less readable to other Python programmers, and it is also conceivable that a class browser program might be written that relies upon such a convention.
Any function object that is a class attribute defines a method for instances of that class. It is not necessary that the function definition is textually enclosed in the class definition: assigning a function object to a local variable in the class is also ok. For example:
Now f , g and h are all attributes of class C that refer to function objects, and consequently they are all methods of instances of C — h being exactly equivalent to g . Note that this practice usually only serves to confuse the reader of a program.
Methods may call other methods by using method attributes of the self argument:
Methods may reference global names in the same way as ordinary functions. The global scope associated with a method is the module containing its definition. (A class is never used as a global scope.) While one rarely encounters a good reason for using global data in a method, there are many legitimate uses of the global scope: for one thing, functions and modules imported into the global scope can be used by methods, as well as functions and classes defined in it. Usually, the class containing the method is itself defined in this global scope, and in the next section we’ll find some good reasons why a method would want to reference its own class.
Each value is an object, and therefore has a class (also called its type ). It is stored as object.__class__ .
9.5. Inheritance ¶
Of course, a language feature would not be worthy of the name “class” without supporting inheritance. The syntax for a derived class definition looks like this:
The name BaseClassName must be defined in a namespace accessible from the scope containing the derived class definition. In place of a base class name, other arbitrary expressions are also allowed. This can be useful, for example, when the base class is defined in another module:
Execution of a derived class definition proceeds the same as for a base class. When the class object is constructed, the base class is remembered. This is used for resolving attribute references: if a requested attribute is not found in the class, the search proceeds to look in the base class. This rule is applied recursively if the base class itself is derived from some other class.
There’s nothing special about instantiation of derived classes: DerivedClassName() creates a new instance of the class. Method references are resolved as follows: the corresponding class attribute is searched, descending down the chain of base classes if necessary, and the method reference is valid if this yields a function object.
Derived classes may override methods of their base classes. Because methods have no special privileges when calling other methods of the same object, a method of a base class that calls another method defined in the same base class may end up calling a method of a derived class that overrides it. (For C++ programmers: all methods in Python are effectively virtual .)
An overriding method in a derived class may in fact want to extend rather than simply replace the base class method of the same name. There is a simple way to call the base class method directly: just call BaseClassName.methodname(self, arguments) . This is occasionally useful to clients as well. (Note that this only works if the base class is accessible as BaseClassName in the global scope.)
Python has two built-in functions that work with inheritance:
Use isinstance() to check an instance’s type: isinstance(obj, int) will be True only if obj.__class__ is int or some class derived from int .
Use issubclass() to check class inheritance: issubclass(bool, int) is True since bool is a subclass of int . However, issubclass(float, int) is False since float is not a subclass of int .
9.5.1. Multiple Inheritance ¶
Python supports a form of multiple inheritance as well. A class definition with multiple base classes looks like this:
For most purposes, in the simplest cases, you can think of the search for attributes inherited from a parent class as depth-first, left-to-right, not searching twice in the same class where there is an overlap in the hierarchy. Thus, if an attribute is not found in DerivedClassName , it is searched for in Base1 , then (recursively) in the base classes of Base1 , and if it was not found there, it was searched for in Base2 , and so on.
In fact, it is slightly more complex than that; the method resolution order changes dynamically to support cooperative calls to super() . This approach is known in some other multiple-inheritance languages as call-next-method and is more powerful than the super call found in single-inheritance languages.
Dynamic ordering is necessary because all cases of multiple inheritance exhibit one or more diamond relationships (where at least one of the parent classes can be accessed through multiple paths from the bottommost class). For example, all classes inherit from object , so any case of multiple inheritance provides more than one path to reach object . To keep the base classes from being accessed more than once, the dynamic algorithm linearizes the search order in a way that preserves the left-to-right ordering specified in each class, that calls each parent only once, and that is monotonic (meaning that a class can be subclassed without affecting the precedence order of its parents). Taken together, these properties make it possible to design reliable and extensible classes with multiple inheritance. For more detail, see https://www.python.org/download/releases/2.3/mro/ .
9.6. Private Variables ¶
“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam ) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.
Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling . Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam , where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.
Name mangling is helpful for letting subclasses override methods without breaking intraclass method calls. For example:
The above example would work even if MappingSubclass were to introduce a __update identifier since it is replaced with _Mapping__update in the Mapping class and _MappingSubclass__update in the MappingSubclass class respectively.
Note that the mangling rules are designed mostly to avoid accidents; it still is possible to access or modify a variable that is considered private. This can even be useful in special circumstances, such as in the debugger.
Notice that code passed to exec() or eval() does not consider the classname of the invoking class to be the current class; this is similar to the effect of the global statement, the effect of which is likewise restricted to code that is byte-compiled together. The same restriction applies to getattr() , setattr() and delattr() , as well as when referencing __dict__ directly.
9.7. Odds and Ends ¶
Sometimes it is useful to have a data type similar to the Pascal “record” or C “struct”, bundling together a few named data items. The idiomatic approach is to use dataclasses for this purpose:
A piece of Python code that expects a particular abstract data type can often be passed a class that emulates the methods of that data type instead. For instance, if you have a function that formats some data from a file object, you can define a class with methods read() and readline() that get the data from a string buffer instead, and pass it as an argument.
Instance method objects have attributes, too: m.__self__ is the instance object with the method m() , and m.__func__ is the function object corresponding to the method.
9.8. Iterators ¶
By now you have probably noticed that most container objects can be looped over using a for statement:
This style of access is clear, concise, and convenient. The use of iterators pervades and unifies Python. Behind the scenes, the for statement calls iter() on the container object. The function returns an iterator object that defines the method __next__() which accesses elements in the container one at a time. When there are no more elements, __next__() raises a StopIteration exception which tells the for loop to terminate. You can call the __next__() method using the next() built-in function; this example shows how it all works:
Having seen the mechanics behind the iterator protocol, it is easy to add iterator behavior to your classes. Define an __iter__() method which returns an object with a __next__() method. If the class defines __next__() , then __iter__() can just return self :
9.9. Generators ¶
Generators are a simple and powerful tool for creating iterators. They are written like regular functions but use the yield statement whenever they want to return data. Each time next() is called on it, the generator resumes where it left off (it remembers all the data values and which statement was last executed). An example shows that generators can be trivially easy to create:
Anything that can be done with generators can also be done with class-based iterators as described in the previous section. What makes generators so compact is that the __iter__() and __next__() methods are created automatically.
Another key feature is that the local variables and execution state are automatically saved between calls. This made the function easier to write and much more clear than an approach using instance variables like self.index and self.data .
In addition to automatic method creation and saving program state, when generators terminate, they automatically raise StopIteration . In combination, these features make it easy to create iterators with no more effort than writing a regular function.
9.10. Generator Expressions ¶
Some simple generators can be coded succinctly as expressions using a syntax similar to list comprehensions but with parentheses instead of square brackets. These expressions are designed for situations where the generator is used right away by an enclosing function. Generator expressions are more compact but less versatile than full generator definitions and tend to be more memory friendly than equivalent list comprehensions.
Except for one thing. Module objects have a secret read-only attribute called __dict__ which returns the dictionary used to implement the module’s namespace; the name __dict__ is an attribute but not a global name. Obviously, using this violates the abstraction of namespace implementation, and should be restricted to things like post-mortem debuggers.
Table of Contents
- 9.1. A Word About Names and Objects
- 9.2.1. Scopes and Namespaces Example
- 9.3.1. Class Definition Syntax
- 9.3.2. Class Objects
- 9.3.3. Instance Objects
- 9.3.4. Method Objects
- 9.3.5. Class and Instance Variables
- 9.4. Random Remarks
- 9.5.1. Multiple Inheritance
- 9.6. Private Variables
- 9.7. Odds and Ends
- 9.8. Iterators
- 9.9. Generators
- 9.10. Generator Expressions
Previous topic
8. Errors and Exceptions
10. Brief Tour of the Standard Library
- Report a Bug
- Show Source
JUnit 5 User Guide
1.1. what is junit 5, 1.2. supported java versions, 1.3. getting help, 1.4.1. downloading junit artifacts, 1.4.2. junit 5 features, 1.4.3. example projects, 2.1.1. meta-annotations and composed annotations, 2.2. definitions, 2.3. test classes and methods, 2.4.1. display name generators, 2.4.2. setting the default display name generator, 2.5.1. kotlin assertion support, 2.5.2. third-party assertion libraries, 2.6. assumptions, 2.7. disabling tests, 2.8.1. operating system and architecture conditions, 2.8.2. java runtime environment conditions, 2.8.3. native image conditions, 2.8.4. system property conditions, 2.8.5. environment variable conditions, 2.8.6. custom conditions, 2.9. tagging and filtering, setting the default method orderer, 2.10.2. class order, 2.11.1. changing the default test instance lifecycle, 2.12. nested tests, 2.13. dependency injection for constructors and methods, 2.14. test interfaces and default methods, 2.15.1. repeated test examples, 2.16.1. required setup, 2.16.2. consuming arguments, @valuesource, null and empty sources, @enumsource, @methodsource, @csvfilesource, @argumentssource, widening conversion, implicit conversion, explicit conversion, custom aggregators, 2.16.6. customizing display names, 2.16.7. lifecycle and interoperability, 2.17. test templates, 2.18.1. dynamic test examples, 2.18.2. uri test sources for dynamic tests, 2.19.1. thread mode, 2.19.2. default timeouts, 2.19.3. using @timeout for polling tests, 2.19.4. disable @timeout globally, relevant properties, 2.20.2. synchronization, 2.21.1. the tempdirectory extension, 3.1.1. categories support, 3.2. migration tips, 3.3. limited junit 4 rule support, 3.4. junit 4 @ignore support, 3.5. failure message arguments, 4.1.1. intellij idea, 4.1.2. eclipse, 4.1.3. netbeans, 4.1.4. visual studio code, 4.1.5. other ides, aligning dependency versions, configuration parameters, configuring test engines, configuring logging (optional), filtering by test class names, filtering by tags, basic usage, 4.2.4. spring boot, discovering tests, executing tests, listing test engines, 4.3.2. argument files (@-files), 4.3.3. color customization, explicit dependencies, transitive dependencies, 4.4.2. display names vs. technical names, 4.4.3. single test class, 4.4.4. test suite, 4.5.1. pattern matching syntax, 4.6.1. syntax rules for tags, 4.6.2. tag expressions, 4.7. capturing standard output/error, 4.8.1. flight recorder support, 4.9. stack trace pruning, 5.1. overview, 5.2.1. declarative extension registration, static fields, instance fields, enabling automatic extension detection, 5.2.4. extension inheritance, pattern matching syntax, 5.4. test instance pre-construct callback, 5.5. test instance factories, 5.6. test instance post-processing, 5.7. test instance pre-destroy callback, 5.8. parameter resolution, 5.9. test result processing, 5.10.1. before and after test execution callbacks, 5.11. exception handling, 5.12. intercepting invocations, 5.13. providing invocation contexts for test templates, 5.14. keeping state in extensions, 5.15.1. annotation support, 5.15.2. class support, 5.15.3. reflection support, 5.15.4. modifier support, 5.16.1. user and extension code, 5.16.2. wrapping behavior of callbacks, 6.1.1. legacy xml format, console launcher, required dependencies, 6.2.2. @suite example, 6.3.1. engine test kit, 6.3.2. asserting statistics, 6.3.3. asserting events, 6.4.1. discovering tests, 6.4.2. executing tests, 6.4.3. registering a testengine, 6.4.4. registering a postdiscoveryfilter, tool support, example usage, 6.4.6. registering a launcherinterceptor, 6.4.7. registering a launcherdiscoverylistener, 6.4.8. registering a testexecutionlistener, 6.4.9. configuring a testexecutionlistener, 6.4.11. configuring the launcher, 6.4.12. dry-run mode, 6.5.1. junit test engines, 6.5.2. custom test engines, 6.5.3. registering a testengine, mandatory requirements, enhanced compatibility, 7.1. api version and status, 7.2. experimental apis, 7.3. deprecated apis, 7.4. @api tooling support, 8. contributors, 9. release notes, 10.1. reproducible builds, 10.2.1. junit platform, 10.2.2. junit jupiter, 10.2.3. junit vintage, 10.2.4. bill of materials (bom), 10.2.5. dependencies, 10.3. dependency diagram, 1. overview.
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 and IDE vendors.
This document is also available as a PDF download .
Unlike previous versions of JUnit, JUnit 5 is composed of several different modules from three different sub-projects.
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
The JUnit Platform serves as a foundation for 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 Console Launcher to launch the platform from the command line and the JUnit Platform Suite Engine 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 IntelliJ IDEA , Eclipse , NetBeans , and Visual Studio Code ) and build tools (see Gradle , Maven , and Ant ).
JUnit Jupiter is the combination of the programming model and extension model for writing tests and extensions in JUnit 5. 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 the platform. It requires JUnit 4.12 or later to be present on the class path or module path.
JUnit 5 requires Java 8 (or higher) at runtime. However, you can still test code that has been compiled with previous versions of the JDK.
Ask JUnit 5 related questions on Stack Overflow or chat with the community on Gitter .
1.4. Getting Started
To find out what artifacts are available for download and inclusion in your project, refer to Dependency Metadata . To set up dependency management for your build, refer to Build Support and the Example Projects .
To find out what features are available in JUnit 5 and how to use them, read the corresponding sections of this User Guide, organized by topic.
Writing Tests in JUnit Jupiter
Migrating from JUnit 4 to JUnit Jupiter
Running Tests
Extension Model for JUnit Jupiter
Advanced Topics
JUnit Platform Launcher API
JUnit Platform Test Kit
To see complete, working examples of projects that you can copy and experiment with, the junit5-samples repository is a good place to start. The junit5-samples repository hosts a collection of sample projects based on JUnit Jupiter, JUnit Vintage, and other testing frameworks. You’ll find appropriate build scripts (e.g., build.gradle , pom.xml , etc.) in the example projects. The links below highlight some of the combinations you can choose from.
For Gradle and Java, check out the junit5-jupiter-starter-gradle project.
For Gradle and Kotlin, check out the junit5-jupiter-starter-gradle-kotlin project.
For Gradle and Groovy, check out the junit5-jupiter-starter-gradle-groovy project.
For Maven, check out the junit5-jupiter-starter-maven project.
For Ant, check out the junit5-jupiter-starter-ant project.
2. 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.
2.1. Annotations
JUnit Jupiter supports the following annotations for configuring tests and extending the framework.
Unless otherwise stated, all core annotations are located in the org.junit.jupiter.api package in the junit-jupiter-api module.
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 Tagging and Filtering ), you can create a custom composed annotation named @Fast as follows. @Fast can then be used as a drop-in replacement for @Tag("fast") .
The following @Test method demonstrates usage of the @Fast annotation.
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 .
JUnit automatically recognizes the following as a @Test method that is tagged with "fast".
a node in the test tree that contains other containers or tests as its children (e.g. a test class ).
a node in the test tree that verifies expected behavior when executed (e.g. a @Test method).
any method that is directly annotated or meta-annotated with @BeforeAll , @AfterAll , @BeforeEach , or @AfterEach .
any top-level class, static member class, or @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.
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 .
Test methods and lifecycle methods may be declared locally within the current test class, inherited from superclasses, or inherited from interfaces (see Test Interfaces and Default Methods ). 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).
The following test class demonstrates the use of @Test methods and all supported lifecycle methods. For further information on runtime semantics, see Test Execution Order and Wrapping Behavior of Callbacks .
2.4. 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.
JUnit Jupiter supports custom display name generators that can be configured via the @DisplayNameGeneration annotation. Values provided via @DisplayName annotations always take precedence over display names generated by a DisplayNameGenerator .
Generators can be created by implementing DisplayNameGenerator . Here are some default ones available in Jupiter:
Note that for IndicativeSentences , you can customize the separator and the underlying generator by using @IndicativeSentencesGeneration as shown in the following example.
You can use the junit.jupiter.displayname.generator.default 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 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 ):
Similarly, you can specify the fully qualified name of any custom class that implements DisplayNameGenerator .
In summary, the display name for a test class or method is determined according to the following precedence rules:
value of the @DisplayName annotation, if present
by calling the DisplayNameGenerator specified in the @DisplayNameGeneration annotation, if present
by calling the default DisplayNameGenerator configured via the configuration parameter, if present
by calling org.junit.jupiter.api.DisplayNameGenerator.Standard
2.5. 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 8 lambdas. All JUnit Jupiter assertions are static methods in the org.junit.jupiter.api.Assertions class.
JUnit Jupiter also comes with a few assertion methods that lend themselves well to being used in Kotlin . All JUnit Jupiter Kotlin assertions are top-level functions in the org.junit.jupiter.api package.
Even though the assertion facilities provided by JUnit Jupiter are sufficient for many testing scenarios, there are times when more power and additional functionality such as matchers 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 combination of matchers and a fluent API can be used to make assertions more descriptive and readable. However, JUnit Jupiter’s org.junit.jupiter.api.Assertions class does not provide an assertThat() method like the one found in JUnit 4’s org.junit.Assert class which accepts a Hamcrest Matcher . Instead, developers are encouraged to use the built-in support for matchers provided by third-party assertion libraries.
The following example demonstrates how to use the assertThat() support from Hamcrest in a JUnit Jupiter test. As long as the Hamcrest library has been added to the classpath, you can statically import methods such as assertThat() , is() , and equalTo() and then use them in tests like in the assertWithHamcrestMatcher() method below.
Naturally, legacy tests based on the JUnit 4 programming model can continue using org.junit.Assert#assertThat .
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 8 lambda expressions and method references. All JUnit Jupiter assumptions are static methods in the org.junit.jupiter.api.Assumptions class.
Entire test classes or individual test methods may be disabled via the @Disabled annotation, via one of the annotations discussed in Conditional Test Execution , or via a custom ExecutionCondition .
Here’s a @Disabled test class.
And here’s a test class that contains a @Disabled test method.
2.8. Conditional Test Execution
The ExecutionCondition extension API in JUnit Jupiter allows developers to either enable or disable a container or test based on certain conditions programmatically . The simplest example of such a condition is the built-in DisabledCondition which supports the @Disabled annotation (see Disabling Tests ). 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 containers and tests declaratively . When multiple ExecutionCondition extensions are registered, a container or test is disabled as soon as one of the conditions returns disabled . 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.
See ExecutionCondition and the following sections for details.
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.
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 defaults to JRE .JAVA_8 as the lower border ( min ) and JRE .OTHER as the higher border ( max ), which allows usage of half open ranges.
A container or test may be enabled or disabled within a 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 Native Build Tools project.
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.
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.
As an alternative to implementing an 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.
The following test class demonstrates how to configure a local method named customCondition via @EnabledIf and @DisabledIf .
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.
Test classes and methods can be tagged via the @Tag annotation. Those tags can later be used to filter test discovery and execution . Please refer to the Tags section for more information about tag support in the JUnit Platform.
2.10. 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.
2.10.1. 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 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 specified via the @Order annotation
MethodOrderer.Random : orders test methods pseudo-randomly and supports configuration of a custom seed
MethodOrderer.Alphanumeric : sorts test methods alphanumerically based on their names and formal parameter lists; deprecated in favor of MethodOrderer.MethodName , to be removed in 6.0
The following example demonstrates how to guarantee that test methods are executed in the order specified via the @Order annotation.
You can use the junit.jupiter.testmethod.order.default 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 @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 ):
Similarly, you can specify the fully qualified name of any custom class that implements MethodOrderer .
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 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 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 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 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 ):
The configured ClassOrderer will be applied to all top-level test classes (including static nested test classes) and @Nested test classes.
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. 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.
2.11. 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 Definitions ). This "per-method" test instance lifecycle is the default behavior in JUnit Jupiter and is analogous to all previous versions of JUnit.
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. The "per-class" mode therefore also makes it possible to use @BeforeAll and @AfterAll methods in @Nested test classes.
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.
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 Configuration Parameters 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
@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.
When executing this example in an IDE, the test execution tree in the GUI will look similar to the following image.

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.
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 Definitions ) 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 test constructor, @BeforeEach method, and @Test method.
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 Repeated Test Examples .
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. The data can be consumed via the reportingEntryPublished() method in a TestExecutionListener , allowing it 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. Using @RunWith(JUnitPlatform.class) will output all reported entries to stdout . In addition, some IDEs print report entries to stdout or display them in the user interface for test results.
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.
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.
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 Test Instance Lifecycle ). Here are some examples.
@ExtendWith and @Tag can be declared on a test interface so that classes that implement the interface automatically inherit its tags and extensions. See Before and After Test Execution Callbacks for the source code of the TimingExtension .
In your test class you can then implement these test interfaces to have them applied.
Running the TestInterfaceDemo results in output similar to the following:
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.
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.
2.15. 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.
Since JUnit Jupiter 5.10, @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.
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.
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.
When using the ConsoleLauncher with the unicode theme enabled, execution of RepeatedTestsDemo results in the following output to the console.
2.16. Parameterized Tests
Parameterized tests make it possible to run a test multiple times with different arguments. They are declared just like regular @Test methods but use the @ParameterizedTest annotation instead. In addition, you must declare at least one source that will provide the arguments for each invocation and then consume the arguments in the test method.
The following example demonstrates a parameterized test that uses the @ValueSource annotation to specify a String array as the source of arguments.
When executing the above parameterized test method, each invocation will be reported separately. For instance, the ConsoleLauncher will print output similar to the following.
In order to use parameterized tests you need to add a dependency on the junit-jupiter-params artifact. Please refer to Dependency Metadata for details.
Parameterized test methods typically consume arguments directly from the configured source (see Sources of Arguments ) following a one-to-one correlation between argument source index and method parameter index (see examples in @CsvSource ). However, a parameterized test method may also choose to aggregate arguments from the source into a single object passed to the method (see Argument Aggregation ). 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 arguments 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 argument 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 .
2.16.3. 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 org.junit.jupiter.params.provider package for additional information.
@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 .
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.
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 @ParameterizedTest method.
@NullSource cannot be used for a parameter that has a primitive type.
@EmptySource : provides a single empty argument to the annotated @ParameterizedTest method 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 test, you can achieve that using @ValueSource — for example, @ValueSource(strings = {" ", " ", "\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.
Making use of the composed @NullAndEmptySource annotation simplifies the above as follows.
@EnumSource provides a convenient way to use Enum constants.
The annotation’s value attribute is optional. When omitted, the declared type of the first method 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.
The annotation provides an optional names attribute that lets you specify which constants shall be used, like in the following example. If omitted, all constants will be used.
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.
@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 @ParameterizedTest method. Generally speaking this translates to a Stream of Arguments (i.e., Stream<Arguments> ); 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 an array of primitives. 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 test method accepts a single argument.
If you only need a single parameter, you can return a Stream of instances of the parameter type as demonstrated in the following example.
If you do not explicitly provide a factory method name via @MethodSource , JUnit Jupiter will search for a factory method that has the same name as the current @ParameterizedTest method by convention. This is demonstrated in the following example.
Streams for primitive types ( DoubleStream , IntStream , and LongStream ) are also supported as demonstrated by the following example.
If a parameterized 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…) .
An external, static factory method can be referenced by providing its fully qualified method name as demonstrated in the following 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)") .
@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 test. The first record may optionally be used to supply CSV headers (see the Javadoc for the useHeadersInDisplayName attribute for details and an 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.
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 .
If the programming language you are using supports text blocks — for example, Java SE 15 or higher — 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 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.
The generated display names for the previous example include the CSV header names.
In contrast to CSV records supplied via the value attribute, a text block can contain comments. Any line beginning with a # symbol will be treated as a comment and ignored. Note, however, that the # symbol 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).
@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 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 following listing shows the generated display names for the first two parameterized test methods above.
The following listing shows the generated display names for the last parameterized test method above that uses CSV header names.
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.
@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.
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.
2.16.4. Argument Conversion
JUnit Jupiter supports Widening Primitive Conversion for arguments supplied to a @ParameterizedTest . For example, a parameterized test 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 .
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 @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.
String instances are implicitly converted to the following target types.
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 a single String 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 single String argument. Note that the target type must be declared as either a top-level class or as a static nested class.
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.
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.
If the converter is only meant to convert one type to another, you can extend TypedArgumentConverter to avoid boilerplate type checks.
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 .
If you wish to implement a custom ArgumentConverter that also consumes an annotation (like JavaTimeArgumentConverter ), you have the possibility to extend the AnnotationBasedArgumentConverter class.
2.16.5. Argument Aggregation
By default, each argument provided to a @ParameterizedTest method corresponds to a single method parameter. Consequently, argument sources which are expected to supply a large number of arguments can lead to large method signatures.
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 Implicit Conversion .
Besides, you can retrieve the current test invocation index with ArgumentsAccessor.getInvocationIndex() .
An instance of ArgumentsAccessor is automatically injected into any parameter of type ArgumentsAccessor .
Apart from direct access to a @ParameterizedTest method’s arguments 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 in the @ParameterizedTest method. 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.
If you find yourself repeatedly declaring @AggregateWith(MyTypeAggregator.class) for multiple parameterized test 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.
By default, the display name of a parameterized test invocation contains the invocation index and the String representation of all arguments for that specific invocation. Each of them is preceded by the parameter name (unless the argument is only available via an ArgumentsAccessor or ArgumentAggregator ), if present in the bytecode (for Java, test code must be compiled with the -parameters compiler flag).
However, you can customize invocation display names via the name attribute of the @ParameterizedTest annotation like in the following example.
When executing the above method using the ConsoleLauncher you will see output similar to the following.
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.
When using @MethodSource or @ArgumentsSource , you can provide custom names for arguments using the Named API. A custom name will be used if the argument is included in the invocation display name, like in the example below.
If you’d like to set a default name pattern for all parameterized 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 Configuration Parameters for other options).
The display name for a parameterized test is determined according to the following precedence rules:
name attribute in @ParameterizedTest , if present
value of the junit.jupiter.params.displayname.default configuration parameter, if present
DEFAULT_DISPLAY_NAME constant defined in @ParameterizedTest
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 Dynamic Tests , 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 argument 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.
A @TestTemplate method is not a regular test case but rather a template for test cases. 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 Providing Invocation Contexts for Test Templates for usage examples.
2.18. Dynamic Tests
The standard @Test annotation in JUnit Jupiter described in Annotations 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 , Collection , Iterable , Iterator , or array of DynamicNode instances. 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 .
As of JUnit Jupiter 5.10.1, dynamic tests must always be created by factory methods; however, this might be complemented by a registration facility in a later release.
The following DynamicTestsDemo class demonstrates several examples of test factories and dynamic tests.
The first method returns an invalid return type. Since an invalid return type cannot be detected at compile time, a JUnitException is thrown when it is detected at runtime.
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 .
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.
If the URI contains the classpath scheme — for example, classpath:/test/foo.xml?line=20,column=2 .
If the URI represents a directory present in the file system.
If the URI represents a file present in the file system.
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.selectMethod(String) for the supported formats for a FQMN.
If the URI contains the class scheme and the fully qualified class name — for example, class:org.junit.Foo?line=42 .
If none of the above TestSource implementations are applicable.
2.19. 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.
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.
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 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.
The following 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 :
Default timeout for all testable and lifecycle methods
Default timeout for all testable methods
Default timeout for @Test methods
Default timeout for @TestTemplate methods
Default timeout for @TestFactory methods
Default timeout for all lifecycle methods
Default timeout for @BeforeAll methods
Default timeout for @BeforeEach methods
Default timeout for @AfterEach methods
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: <number> [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.
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.
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.
2.20. Parallel Execution
By default, JUnit Jupiter tests are run sequentially in a single thread. Running tests in parallel — for example, to speed up execution — is available as an opt-in feature since version 5.3. To enable parallel execution, set the junit.jupiter.execution.parallel.enabled configuration parameter to true — for example, in junit-platform.properties (see Configuration Parameters 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.
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.
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.
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 (except for MethodOrderer.Random ). 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.
When parallel execution is enabled and a default ClassOrderer is registered (see 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 configuration while observing the declarative synchronization mechanism. Please note that Capturing Standard Output/Error 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:
The opposite combination will run all methods within one class in parallel, but top-level classes will run sequentially:
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).
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.
2.20.1. Configuration
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.
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.
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.
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.
The following table lists relevant properties for configuring parallel execution. See Configuration Parameters for details on how to set such properties.
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 .
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.
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.
2.21. Built-in Extensions
While the JUnit team encourages reusable extensions to be packaged and maintained in separate libraries, the JUnit Jupiter API artifact includes a few user-facing extension implementations that are considered so generally useful that users shouldn’t have to add another dependency.
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 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.
You can inject multiple temporary directories by specifying multiple annotated parameters.
@TempDir is not supported on constructor parameters. If you wish to retain a single reference to a temp directory across lifecycle methods and the current test method, please use field injection by annotating an instance field with @TempDir .
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 so that each test method uses a separate directory.
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 , temporary directories are not deleted after a test completes. If it is set to ON_SUCCESS , temporary directories are deleted only after a test completed successfully.
The default cleanup mode is ALWAYS . You can use the junit.jupiter.tempdir.cleanup.mode.default configuration parameter to override this default.
@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 the directory creation to java.nio.file.Files::createTempDirectory , passing junit as the prefix string to be used in generating the directory’s name.
The following example defines a factory that uses the test name as the directory name prefix instead of the junit constant value.
It’s 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.
@TempDir can also be used as a 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) .
The following example demonstrates how to use the custom @JimfsTempDir annotation.
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 createTempDirectory .
You can use the junit.jupiter.tempdir.factory.default 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 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:
The factory attribute of the @TempDir annotation, if present
The default TempDirFactory configured via the configuration parameter, if present
Otherwise, org.junit.jupiter.api.io.TempDirFactory$Standard will be used.
3. 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 maintainers will need to update all of their existing tests, test extensions, and custom build test infrastructure to migrate to JUnit Jupiter.
Instead, JUnit provides a gentle migration path via a JUnit Vintage test engine which allows existing tests based on JUnit 3 and JUnit 4 to be executed using the JUnit Platform infrastructure. Since all classes and annotations specific to JUnit Jupiter reside under the org.junit.jupiter base package, having both JUnit 4 and JUnit Jupiter in the classpath does not lead to any conflicts. It is therefore safe to maintain existing JUnit 4 tests alongside JUnit Jupiter tests. Furthermore, since the JUnit team will continue to provide maintenance and bug fix releases for the JUnit 4.x baseline, developers have plenty of time to migrate to JUnit Jupiter on their own schedule.
3.1. Running JUnit 4 Tests on the JUnit Platform
Make sure that the junit-vintage-engine artifact is in your test runtime path. In that case JUnit 3 and JUnit 4 tests will automatically be picked up by the JUnit Platform launcher.
See the example projects in the junit5-samples repository to find out how this is done with Gradle and Maven.
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 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 Running Tests for details).
The following are topics that you should be aware of when migrating existing JUnit 4 tests to JUnit Jupiter.
Annotations reside in the org.junit.jupiter.api package.
Assertions reside in org.junit.jupiter.api.Assertions .
Note that you may continue to use assertion methods from org.junit.Assert or any other assertion library such as AssertJ , Hamcrest , Truth , etc.
Assumptions reside in org.junit.jupiter.api.Assumptions .
Note that JUnit Jupiter 5.4 and later versions support 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.
@Before and @After no longer exist; use @BeforeEach and @AfterEach instead.
@BeforeClass and @AfterClass no longer exist; use @BeforeAll and @AfterAll instead.
@Ignore no longer exists: use @Disabled or one of the other built-in execution conditions instead
See also JUnit 4 @Ignore Support .
@Category no longer exists; use @Tag instead.
@RunWith no longer exists; superseded by @ExtendWith .
@Rule and @ClassRule no longer exist; superseded by @ExtendWith and @RegisterExtension .
See also Limited JUnit 4 Rule Support .
@Test(expected = …) and the ExpectedException rule no longer exist; use Assertions.assertThrows(…) instead.
See Limited JUnit 4 Rule Support 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 Failure Message Arguments for details.
As stated above, JUnit Jupiter does not and will not support JUnit 4 rules natively. The JUnit team realizes, however, that many organizations, especially large ones, are likely to have large JUnit 4 code bases that make use of custom rules. To serve these organizations and enable a gradual migration path the JUnit team has decided to support a selection of JUnit 4 rules verbatim within JUnit Jupiter. This support is based on adapters and is limited to those rules that are semantically compatible to the JUnit Jupiter extension model, i.e. those that do not completely change the overall execution flow of the test.
The junit-jupiter-migrationsupport module from JUnit Jupiter currently supports the following three Rule types including subclasses of these types:
org.junit.rules.ExternalResource (including org.junit.rules.TemporaryFolder )
org.junit.rules.Verifier (including org.junit.rules.ErrorCollector )
org.junit.rules.ExpectedException
As in JUnit 4, Rule-annotated fields as well as methods are supported. By using these class-level extensions on a test class such Rule implementations in legacy code bases can be left unchanged including the JUnit 4 rule import statements.
This limited form of Rule support can be switched on by the class-level annotation @EnableRuleMigrationSupport . This annotation is a composed annotation which enables 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 JUnit 4 @Ignore Support ).
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.
In order to provide a smooth migration path from JUnit 4 to JUnit Jupiter, the junit-jupiter-migrationsupport module provides support for JUnit 4’s @Ignore annotation analogous to Jupiter’s @Disabled annotation.
To use @Ignore with JUnit Jupiter based tests, configure a test dependency on the 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 Limited JUnit 4 Rule Support ). The IgnoreCondition is an ExecutionCondition that disables test classes or test methods that are annotated with @Ignore .
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 failure message as the first argument; whereas, in JUnit Jupiter assertion and assumption methods accept the failure message as the last argument.
For instance, the method assertEquals in JUnit 4 is declared as assertEquals(String message, Object expected, Object actual) , but in JUnit Jupiter it is declared as assertEquals(Object expected, Object actual, String message) . The rationale for this is that a failure message is optional , and optional arguments should be declared after required arguments in a method signature.
The methods affected by this change are the following:
assertFalse
assertNotNull
assertEquals
assertNotEquals
assertArrayEquals
assertNotSame
assertThrows
Assumptions
assumeFalse
4. Running Tests
4.1. ide support.
IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For details please see the post on the IntelliJ IDEA blog . Note, however, that it is recommended to use IDEA 2017.3 or newer since these newer versions of IDEA will 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 5 version (e.g., 5.10.1), you may need to include the corresponding versions of the junit-platform-launcher , junit-jupiter-engine , and junit-vintage-engine JARs in the classpath.
Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) release.
For more information on using JUnit 5 in Eclipse consult the official Eclipse support for JUnit 5 section of the Eclipse Project Oxygen.1a (4.7.1a) - New and Noteworthy documentation.
NetBeans offers support for JUnit Jupiter and the JUnit Platform since the Apache NetBeans 10.0 release .
For more information consult the JUnit 5 section of the Apache NetBeans 10.0 release notes .
Visual Studio Code supports JUnit Jupiter and the JUnit Platform via the Java Test Runner extension which is installed by default as part of the Java Extension Pack .
For more information consult the Testing section of the Java in Visual Studio Code documentation.
If you are using an editor or IDE other than one of those listed in the previous sections, the JUnit team provides two alternative solutions to assist you in using JUnit 5. You can use the Console Launcher manually — for example, from the command line — or execute tests with a JUnit 4 based Runner if your IDE has built-in support for JUnit 4.
4.2. Build Support
4.2.1. gradle.
Starting with version 4.6 , Gradle provides 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 :
Filtering by tags , tag expressions , or engines is also supported:
Please refer to the official Gradle documentation for a comprehensive list of options.
Unless you’re using Spring Boot which defines its own way of managing dependencies, it is recommended to use the JUnit Platform BOM to align the versions of all JUnit 5 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.
The standard Gradle test task currently does not provide a dedicated DSL to set JUnit Platform 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.
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.
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.
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 2.x (see Log4j JDK Logging Adapter for details).
Other logging frameworks provide different means to redirect messages logged using java.util.logging . For example, for Logback you can use the JUL to SLF4J Bridge by adding an additional dependency to the runtime classpath.
4.2.2. Maven
Starting with version 2.22.0 , Maven Surefire and Maven Failsafe provide native support for executing tests on the JUnit Platform. The pom.xml file in the junit5-jupiter-starter-maven project demonstrates how to use the Maven Surefire plugin and can serve as a starting point for configuring your Maven build.
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.
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.
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.
Please see the Inclusions and Exclusions of Tests documentation for Maven Surefire for details.
You can filter tests by tags or tag expressions using the following configuration properties.
to include tags or tag expressions , use groups .
to exclude tags or tag expressions , use excludedGroups .
You can set JUnit Platform 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.
Starting with version 1.10.3 , Ant has a 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 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 forking the tests in a separate JVM .
The build.xml file in the junit5-jupiter-starter-ant project demonstrates how to use the task and can serve as a starting point.
The following example demonstrates how to configure the junitlauncher task to select a single test class (i.e., org.myapp.test.MyFirstJUnit5Test ).
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.
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 junitlauncher task .
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 the junit-bom in your build script since that will 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 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 Gradle and Maven .
With Gradle you can override the JUnit Jupiter version by including the following in your build.gradle file.
With Maven you can override the JUnit Jupiter version by including the following in your pom.xml file.
4.3. 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 junit-platform-console-standalone-1.10.1.jar with all dependencies included is published in the Maven Central repository under the junit-platform-console-standalone directory. It includes the following dependencies:
junit:junit:4.13.2
org.apiguardian:apiguardian-api:1.1.2
org.hamcrest:hamcrest-core:1.3
org.junit.jupiter:junit-jupiter-api:5.10.1
org.junit.jupiter:junit-jupiter-engine:5.10.1
org.junit.jupiter:junit-jupiter-params:5.10.1
org.junit.platform:junit-platform-commons:1.10.1
org.junit.platform:junit-platform-console:1.10.1
org.junit.platform:junit-platform-engine:1.10.1
org.junit.platform:junit-platform-launcher:1.10.1
org.junit.platform:junit-platform-reporting:1.10.1
org.junit.platform:junit-platform-suite-api:1.10.1
org.junit.platform:junit-platform-suite-commons:1.10.1
org.junit.platform:junit-platform-suite-engine:1.10.1
org.junit.platform:junit-platform-suite:1.10.1
org.junit.vintage:junit-vintage-engine:5.10.1
org.opentest4j:opentest4j:1.3.0
You can run the standalone ConsoleLauncher as shown below.
You can also run the standalone ConsoleLauncher as shown below (for example, to include all jars in a directory):
4.3.1. Subcommands and Options
The ConsoleLauncher provides the following subcommands:
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.
Since version 1.3, 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 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.
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 ANSI SGR color styling. The properties file below demonstrates the default style:
4.4. Using JUnit 4 to run the JUnit Platform
The JUnitPlatform runner is a JUnit 4 based Runner which enables you to run any test whose programming model is supported on the JUnit Platform in a JUnit 4 environment — for example, a JUnit Jupiter test class.
Annotating a class with @RunWith(JUnitPlatform.class) allows it to be run with IDEs and build systems that support JUnit 4 but do not yet support the JUnit Platform directly.
4.4.1. Setup
You need the following artifacts and their dependencies on the classpath. See Dependency Metadata for details regarding group IDs, artifact IDs, and versions.
junit-platform-runner in test scope: location of the JUnitPlatform runner
junit-4.13.2.jar in test scope: to run tests using JUnit 4
junit-jupiter-api in test scope: API for writing tests using JUnit Jupiter, including @Test , etc.
junit-jupiter-engine in test runtime scope: implementation of the TestEngine API for JUnit Jupiter
junit-platform-suite-api in test scope
junit-platform-suite-commons in test scope
junit-platform-launcher in test scope
junit-platform-engine in test scope
junit-platform-commons in test scope
opentest4j in test scope
To define a custom display name for the class run via @RunWith(JUnitPlatform.class) annotate the class with @SuiteDisplayName and provide a custom value.
By default, display names will be used for test artifacts; however, when the JUnitPlatform runner is used to execute tests with a build tool such as Gradle or Maven, the generated test report often needs to include the technical names of test artifacts — for example, fully qualified class names — instead of shorter display names like the simple name of a test class or a custom display name containing special characters. To enable technical names for reporting purposes, declare the @UseTechnicalNames annotation alongside @RunWith(JUnitPlatform.class) .
Note that the presence of @UseTechnicalNames overrides any custom display name configured via @SuiteDisplayName .
One way to use the JUnitPlatform runner is to annotate a test class with @RunWith(JUnitPlatform.class) directly. Please note that the test methods in the following example are annotated with org.junit.jupiter.api.Test (JUnit Jupiter), not org.junit.Test (JUnit 4). Moreover, in this case the test class must be public ; otherwise, some IDEs and build tools might not recognize it as a JUnit 4 test class.
If you have multiple test classes you can create a test suite as can be seen in the following example.
The JUnitPlatformSuiteDemo will discover and run all tests in the example package and its subpackages. By default, it will only include test classes whose names either begin with Test or end with Test or Tests .
4.5. 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.
Changing the Default Test Instance Lifecycle
Deactivating Conditions
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.
The configurationParameter() and configurationParameters() methods in the LauncherDiscoveryRequestBuilder which is used to build a request supplied to the Launcher API . When running tests via one of the tools provided by the JUnit Platform you can specify configuration parameters as follows:
Console Launcher : use the --config command-line option.
Gradle : use the systemProperty or systemProperties DSL.
Maven Surefire provider : use the configurationParameters property.
JVM system properties.
The JUnit Platform configuration file: a file named junit-platform.properties in the root of the class path that follows the syntax rules for a Java Properties file.
This section describes the pattern matching syntax that is applied to the configuration parameters used for the following features.
Deactivating a TestExecutionListener
Stack Trace Pruning
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.
* : 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 .
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 Tagging and Filtering ) should be used. For JUnit 4 based tests, the Vintage engine maps @Category annotations to tags (see Categories Support ). Other testing frameworks may define their own annotation or other means for users to specify tags.
Regardless how a tag is specified, the JUnit Platform enforces the following rules:
A tag must not be null or blank .
A trimmed tag must not contain whitespace.
A trimmed tag must not contain ISO control characters.
A trimmed tag must not contain any of the following reserved characters .
( : left parenthesis
) : right parenthesis
& : ampersand
| : vertical bar
! : exclamation point
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.
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.
Since version 1.3, 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 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 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 executing tests in parallel it would be impossible to attribute it to a specific test or container.
4.8. 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.
Registering a LauncherSessionListener
Registering a LauncherInterceptor
Registering a LauncherDiscoveryListener
Registering a TestExecutionListener
Configuring a TestExecutionListener
The JUnit Platform provides the following listeners which you may wish to use with your test suite.
LegacyXmlReportGeneratingListener can be used via the Console Launcher 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 Open Test Reporting . It is auto-registered and can be enabled and configured via Configuration Parameters .
See JUnit Platform Reporting for details.
FlightRecordingExecutionListener and FlightRecordingDiscoveryListener that generate Java Flight Recorder events during test discovery and execution.
TestExecutionListener for logging informational messages for all events via a BiConsumer that consumes Throwable and Supplier<String> .
TestExecutionListener that generates a summary of the test execution which can be printed via a PrintWriter .
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.
Since version 1.7, the JUnit Platform provides opt-in support for generating Flight Recorder events. JEP 328 describes the Java Flight Recorder (JFR) as:
In order to record Flight Recorder events generated while running tests, you need to:
Ensure that you are using either Java 8 Update 262 or higher or Java 11 or later.
Provide the org.junit.platform.jfr module ( junit-platform-jfr-1.10.1.jar ) on the class-path or module-path at test runtime.
Start flight recording when launching a test run. Flight Recorder can be started via java command line option:
Please consult the manual of your build tool for the appropriate commands.
To analyze the recorded events, use the jfr command line tool shipped with recent JDKs or open the recording file with JDK Mission Control .
Since version 1.10, 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 org.junit.jupiter.api.Assertions or org.junit.jupiter.api.Assumptions will never be excluded.
In addition, all elements prior to and including the first call from the JUnit Platform Launcher will be removed.
5. 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.
5.2. Registering Extensions
Extensions can be registered declaratively via @ExtendWith , programmatically via @RegisterExtension , or automatically via Java’s ServiceLoader mechanism.
Developers can register one or more extensions declaratively by annotating a test interface, test class, test method, or custom composed annotation with @ExtendWith(…) and supplying class references for the extensions to register. As of JUnit Jupiter 5.8, @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 .
To register the WebServerExtension for all tests in a particular class and its subclasses, you would annotate the test class as follows.
Multiple extensions can be registered together like this:
As an alternative, multiple extensions can be registered separately like this:
If you wish to combine multiple extensions in a reusable way, you can define a custom 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 }) .
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.
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
BeforeEachCallback : to support non-static field injection
ParameterResolver : to support constructor and method injection
5.2.2. Programmatic Extension Registration
Developers can register extensions programmatically by annotating fields in test classes with @RegisterExtension .
When an extension is registered declaratively via @ExtendWith , 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.
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.
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.
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. By default, an instance extension will be registered after extensions that are registered at the method level via @ExtendWith ; however, if the test class is configured with @TestInstance(Lifecycle.PER_CLASS) semantics, an instance extension 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.
5.2.3. Automatic Extension Registration
In addition to declarative extension registration and programmatic extension registration 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.
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 Configuration Parameters 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.).
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. Furthermore, 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.
5.3. 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.
5.3.1. 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 Configuration Parameters 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
Refer to Pattern Matching Syntax for details.
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.
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.
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 .
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.
ParameterResolver defines the Extension API for dynamically resolving parameters at runtime.
If a test class constructor, test method , or lifecycle method (see Definitions ) declares a parameter, the parameter must be resolved at runtime by a ParameterResolver . A ParameterResolver can either be built-in (see TestInfoParameterResolver ) or registered by the user . 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 .
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
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.
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.
5.10. 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 org.junit.jupiter.api.extension package for further details.
BeforeAllCallback
BeforeEachCallback
BeforeTestExecutionCallback
AfterTestExecutionCallback
AfterEachCallback
AfterAllCallback
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.
Since the TimingExtensionTests class registers the TimingExtension via @ExtendWith , its tests will have this timing applied when they execute.
The following is an example of the logging produced when TimingExtensionTests is run.
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.
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 .
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.
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.
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 .
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.
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 Repeated Tests or Parameterized Tests which use this extension point to provide their functionality.
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 Store exactly for this purpose. Extensions may put values into a store for later retrieval. See the TimingExtension for an example of using the Store with a method-level scope. It is important to remember that values stored in an ExtensionContext during test execution will not be available in the surrounding ExtensionContext . Since ExtensionContexts may be nested, the scope of inner contexts may also be limited. Consult the corresponding Javadoc for details on the methods available for storing and retrieving values via the Store .
5.15. Supported Utilities in Extensions
The junit-platform-commons artifact exposes a package named org.junit.platform.commons.support that contains maintained utility methods for working with annotations, classes, reflection, and classpath scanning tasks. TestEngine and Extension authors are encouraged to use these supported methods in order to align with the behavior of the JUnit Platform.
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.
ClassSupport provides static utility methods for working with classes (i.e., instances of java.lang.Class ). Consult the Javadoc for ClassSupport for further details.
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.
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.
5.16. 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.
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.

The following table further explains the sixteen steps in the User code and extension code diagram.
In the simplest case only the actual test method will be executed (step 8); 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 InvocationInterceptor .
JUnit Jupiter always guarantees wrapping behavior for multiple registered extensions that implement lifecycle callbacks such as BeforeAllCallback , AfterAllCallback , 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 Definitions ).
@BeforeAll methods are inherited from superclasses as long as they are not hidden , overridden , or superseded (i.e., replaced based on signature only, irrespective of Java’s visibility rules). 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 hidden or 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 hidden , overridden , or superseded (i.e., replaced based on signature only, irrespective of Java’s visibility rules). 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 hidden or 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 or superseded (i.e., replaced based on signature only, irrespective of Java’s visibility rules). 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 or superseded (i.e., replaced based on signature only, irrespective of Java’s visibility rules). 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.
When the DatabaseTestsDemo test class is executed, the following is logged.
The following sequence diagram helps to shed further light on what actually goes on within the JupiterTestEngine when the DatabaseTestsDemo test class is executed.

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.
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.
When the BrokenLifecycleMethodConfigDemo test class is executed, the following is logged.
The following sequence diagram helps to shed further light on what actually goes on within the JupiterTestEngine when the BrokenLifecycleMethodConfigDemo test class is executed.

6. Advanced Topics
6.1. junit platform reporting.
The junit-platform-reporting artifact contains TestExecutionListener implementations that generate XML test reports in two flavors: legacy and Open Test Reporting .
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 Console Launcher as well.
6.1.2. Open Test Reporting XML format
OpenTestReportGeneratingListener writes an XML report for the entire execution in the event-based format specified by Open Test Reporting which supports all features of the JUnit Platform such as hierarchical test structures, display names, tags, etc.
The listener is auto-registered and can be configured via the following Configuration Parameters :
Enable/disable writing the report.
Configure the output directory for the reports. By default, build is used if a Gradle build script is found, and target if a Maven POM is found; otherwise, the current working directory is used.
If enabled, the listener creates an XML report file named junit-platform-events-<random-id>.xml per test run in the configured output directory.
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 be the same directory Gradle uses for its own XML reports. A CommandLineArgumentProvider is used to keep the tasks relocatable across different machines which is important when using Gradle’s Build Cache.
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 XML reports as follows:
When using the Console Launcher , you can enable Open Test Reporting output by setting the configuration parameters via --config :
6.2. JUnit Platform Suite Engine
The JUnit Platform supports the declarative definition and execution of suites of tests from any test engine using the JUnit Platform.
6.2.1. 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 Dependency Metadata for details regarding group IDs, artifact IDs, and versions.
junit-platform-suite-api in test scope: artifact containing annotations needed to configure a test suite
junit-platform-suite-engine in test runtime scope: implementation of the TestEngine API for declarative test suites
By annotating a class with @Suite it is marked as a test suite on the JUnit Platform. As seen in the following example, selector and filter annotations can then be used to control the contents of the suite.
6.3. 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. As of JUnit Platform 1.4, this support is limited to the execution of a single TestEngine (see Engine Test Kit ).
The org.junit.platform.testkit.engine package provides support for executing a TestPlan for a given TestEngine running on the JUnit Platform and then accessing the results via a fluent API to verify the expected results. The key entry point into this API is the EngineTestKit which provides static factory methods named engine() and execute() . It is recommended that you select one of the engine() variants to benefit from the fluent API for building a LauncherDiscoveryRequest .
The following test class written using JUnit Jupiter will be used in subsequent examples.
For the sake of brevity, the following sections demonstrate how to test JUnit’s own JupiterTestEngine whose unique engine ID is "junit-jupiter" . If you want to test your own TestEngine implementation, you need to use its unique engine ID. Alternatively, you may test your own TestEngine by supplying an instance of it to the EngineTestKit.engine(TestEngine) static factory method.
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 how to assert statistics for containers and tests in the JUnit Jupiter TestEngine . For details on what statistics are available, consult the Javadoc for EventStatistics .
If you find that asserting statistics 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 ExampleTestCase was skipped, you can do that as follows.
If you want to verify the type of exception thrown from the failingTest() method in ExampleTestCase , you can do that as follows.
Although typically unnecessary, there are times when you need to verify all of the events fired during the execution of a TestPlan . The following test demonstrates how to achieve this via the assertEventsMatchExactly() method in the EngineTestKit API.
If you want to do a partial match with or without ordering requirements, you can use the methods assertEventsMatchLooselyInOrder() and assertEventsMatchLoosely() , respectively.
The debug() invocation from the preceding example results in output similar to the following.
6.4. JUnit Platform Launcher API
One of the prominent goals of JUnit 5 is to make the interface between JUnit and its programmatic clients – build tools and IDEs – more powerful and stable. The purpose is to decouple the internals of discovering and executing tests from all the filtering and configuration that’s necessary from the outside.
JUnit 5 introduces the concept of a Launcher that can be used to discover, filter, and execute tests. Moreover, third party test libraries – like Spock, Cucumber, and FitNesse – can plug into the JUnit Platform’s launching infrastructure by providing a custom TestEngine .
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.
Having test discovery as a dedicated feature of the platform itself frees IDEs and build tools from most of the difficulties they had to go through to identify test classes and test methods in previous versions of JUnit.
Usage Example:
You can select classes, methods, and all classes in a package or even search for all tests in the class-path or module-path. Discovery takes place across all participating test engines.
The resulting TestPlan is a hierarchical (and read-only) description of all engines, classes, and test methods that fit the LauncherDiscoveryRequest . The client can traverse the tree, retrieve details about a node, and get a link to the original source (like class, method, or file position). Every node in the test plan has a unique ID that can be used to invoke a particular test or group of tests.
Clients can register one or more LauncherDiscoveryListener implementations via the LauncherDiscoveryRequestBuilder to gain insight into events that occur during test 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 configuration parameter .
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 one or more TestExecutionListener implementations with the Launcher as in the following example.
There is no return value for the execute() method, but you can use a TestExecutionListener to aggregate the results. For examples see the SummaryGeneratingListener , LegacyXmlReportGeneratingListener , and UniqueIdTrackingListener .
See the dedicated section on TestEngine registration for details.
In addition to specifying post-discovery filters as part of a LauncherDiscoveryRequest passed to the Launcher API, PostDiscoveryFilter implementations will be discovered at runtime via Java’s ServiceLoader mechanism and automatically applied by the Launcher in addition to those that are part of the request.
For example, an example.CustomTagFilter class implementing PostDiscoveryFilter and declared within the /META-INF/services/org.junit.platform.launcher.PostDiscoveryFilter file is loaded and applied automatically.
6.4.5. Registering a LauncherSessionListener
Registered implementations of LauncherSessionListener are notified when a LauncherSession is opened (before a Launcher first discovers and executes tests) and closed (when no more tests will be discovered or executed). They can be registered programmatically via the LauncherConfig that is passed to the LauncherFactory , or they can be discovered at runtime via Java’s ServiceLoader mechanism and automatically registered with LauncherSession (unless automatic registration is disabled.)
The following build tools and IDEs are known to provide full support for LauncherSession :
Gradle 4.6 and later
Maven Surefire/Failsafe 3.0.0-M6 and later
IntelliJ IDEA 2017.3 and later
Other tools might also work but have not been tested explicitly.
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, respectively. The scope of a launcher session depends on the used IDE or build tool but usually corresponds to the lifecycle of the test JVM. A custom listener that starts an HTTP server before executing the first test and stops it after the last test has been executed, could look like this:
This sample uses the HTTP server implementation from the jdk.httpserver module that comes with the JDK but would work similarly with any other server or resource. In order for the listener to be picked up by JUnit Platform, you need to register it as a service by adding a resource file with the following name and contents to your test runtime classpath (e.g. by adding the file to src/test/resources ):
You can now use the resource from your test:
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 additionally setting the junit.platform.launcher.interceptors.enabled configuration parameter to true .
A typical use case is to create a custom replace the ClassLoader used by the JUnit Platform to load test classes and engine implementations.
In addition to specifying discovery listeners as part of a LauncherDiscoveryRequest or registering them programmatically via the Launcher API, custom LauncherDiscoveryListener implementations can be discovered at runtime via Java’s ServiceLoader mechanism and automatically registered with the Launcher created via the LauncherFactory .
For example, an example.CustomLauncherDiscoveryListener class implementing LauncherDiscoveryListener and declared within the /META-INF/services/org.junit.platform.launcher.LauncherDiscoveryListener file is loaded and registered automatically.
In addition to the public Launcher API method for registering test execution listeners programmatically, custom TestExecutionListener implementations will be discovered at runtime via Java’s ServiceLoader mechanism and automatically registered with the Launcher created via the LauncherFactory .
For example, an example.CustomTestExecutionListener class implementing TestExecutionListener and declared within the /META-INF/services/org.junit.platform.launcher.TestExecutionListener file is loaded and registered automatically.
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 Registering a TestExecutionListener ), 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 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.
6.4.10. 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 results to an external system for reporting purposes, and while debugging you might not want these debug results to be reported. To do this, provide a pattern for the junit.platform.execution.listeners.deactivate configuration parameter to specify which execution listeners should be deactivated (i.e. not registered) for the current test run.
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 the LauncherFactory . Typically, an instance of LauncherConfig is created via the built-in fluent builder API, as demonstrated in the following example.
When running tests via the Launcher API, you can enable dry-run mode by setting the junit.platform.execution.dryRun.enabled 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.
6.5. Test Engines
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 Writing Tests and Extension Model ).
JUnit provides three TestEngine implementations.
junit-jupiter-engine : The core of JUnit Jupiter.
junit-vintage-engine : A thin layer on top of JUnit 4 to allow running vintage tests (based on JUnit 3.8 and JUnit 4) with the JUnit Platform launcher infrastructure.
junit-platform-suite-engine : Executes declarative suites of tests with the JUnit Platform launcher infrastructure.
You can contribute your own custom TestEngine by implementing the interfaces in the junit-platform-engine module and registering your engine.
Every TestEngine must provide its own unique ID , discover tests from an EngineDiscoveryRequest , and execute those tests according to an ExecutionRequest .
In order to facilitate test discovery within IDEs and tools prior to launching the JUnit Platform, TestEngine implementations are encouraged to make use of the @Testable annotation. For example, the @Test and @TestFactory annotations in JUnit Jupiter are 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 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 addition, since configuration parameters may be supplied as JVM system properties, it is wise to avoid conflicts with the names of other system properties. For example, JUnit Jupiter uses junit.jupiter. as a prefix of all of its supported configuration parameters. Furthermore, as with the warning above regarding the junit- prefix for TestEngine IDs, you should not use junit. as a prefix for the names of your own configuration parameters.
Although there is currently no official guide on how to implement a custom TestEngine , you can consult the implementation of JUnit Test Engines or the implementation of third-party test engines listed in the JUnit 5 wiki . You will also find various tutorials and blogs on the Internet that demonstrate how to write a custom TestEngine .
TestEngine registration is supported via Java’s ServiceLoader mechanism.
For example, the junit-jupiter-engine module registers its org.junit.jupiter.engine.JupiterTestEngine in a file named org.junit.platform.engine.TestEngine within the /META-INF/services folder in the junit-jupiter-engine JAR.
6.5.4. Requirements
For interoperability with build tools and IDEs, TestEngine implementations must adhere to the following requirements:
The TestDescriptor returned from TestEngine.discover() must be the root of a tree of TestDescriptor instances. This implies that there must not be any cycles between a node and its descendants.
A TestEngine must be able to discover UniqueIdSelectors for any unique ID that it previously generated and returned from TestEngine.discover() . This enables selecting a subset of tests to execute or rerun.
The executionSkipped , executionStarted , and executionFinished methods of the EngineExecutionListener passed to TestEngine.execute() must be called for every TestDescriptor node in the tree returned from TestEngine.discover() at most once. Parent nodes must be reported as started before their children and as finished after their children. If a node is reported as skipped, there must not be any events reported for its descendants.
Adhering to the following requirements is optional but recommended for enhanced compatibility with build tools and IDEs:
Unless to indicate an empty discovery result, the TestDescriptor returned from TestEngine.discover() should have children rather than being completely dynamic. This allows tools to display the structure of the tests and to select a subset of tests to execute.
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 tagging tests and containers so that tag filters can be applied when discovering tests.
7. API Evolution
One of the major goals of JUnit 5 is to improve maintainers' capabilities to evolve JUnit despite its being used in many projects. With JUnit 4 a lot of stuff that was originally added as an internal construct only got used by external extension writers and tool builders. That made changing JUnit 4 especially difficult and sometimes impossible.
That’s why JUnit 5 introduces a defined lifecycle for all publicly available interfaces, classes, and methods.
Every published artifact has a version number <major>.<minor>.<patch> , and all publicly available interfaces, classes, and methods are annotated with @API from the @API Guardian project. The annotation’s status attribute can be assigned one of the following values.
If the @API annotation is present on a type, it is considered to be applicable for all public members of that type as well. A member is allowed to declare a different status value of lower stability.
The following table lists which APIs are currently designated as experimental via @API(status = EXPERIMENTAL) . Caution should be taken when relying on such APIs.
The following table lists 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.
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 means to check if JUnit APIs are being used in accordance with @API annotation declarations.
Browse the current list of contributors directly on GitHub.
The release notes are available here .
10. Appendix
Starting with version 5.7, JUnit 5 aims for its non-javadoc JARs to be reproducible .
Under identical build conditions, such as Java version, repeated builds should provide the same output byte-for-byte.
This means that anyone can reproduce the build conditions of the artifacts on Maven Central/Sonatype and produce the same output artifact locally, confirming that the artifacts in the repositories were actually generated from this source code.
10.2. Dependency Metadata
Artifacts for final releases and milestones are deployed to Maven Central , and snapshot artifacts are deployed to Sonatype’s snapshots repository under /org/junit .
Group ID : org.junit.platform
Version : 1.10.1
Artifact IDs :
Common APIs and support utilities for the JUnit Platform. Any API annotated with @API(status = INTERNAL) is intended solely for usage within the JUnit framework itself. Any usage of internal APIs by external parties is not supported!
Support for discovering and executing tests on the JUnit Platform from the console. See Console Launcher for details.
An executable JAR with all dependencies included is provided in Maven Central under the junit-platform-console-standalone directory. See Console Launcher for details.
Public API for test engines. See Registering a TestEngine for details.
Provides a LauncherDiscoveryListener and TestExecutionListener for Java Flight Recorder events on the JUnit Platform. See Flight Recorder Support for details.
Public API for configuring and launching test plans — typically used by IDEs and build tools. See JUnit Platform Launcher API for details.
TestExecutionListener implementations that generate test reports — typically used by IDEs and build tools. See JUnit Platform Reporting for details.
Runner for executing tests and test suites on the JUnit Platform in a JUnit 4 environment. See Using JUnit 4 to run the JUnit Platform for details.
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.
Annotations for configuring test suites on the JUnit Platform. Supported by the JUnit Platform Suite Engine and the JUnitPlatform runner .
Common support utilities for executing test suites on the JUnit Platform.
Engine that executes test suites on the JUnit Platform; only required at runtime. See JUnit Platform Suite Engine for details.
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.
Group ID : org.junit.jupiter
Version : 5.10.1
JUnit Jupiter aggregator artifact that transitively pulls in dependencies on junit-jupiter-api , junit-jupiter-params , and junit-jupiter-engine for simplified dependency management in build tools such as Gradle and Maven.
JUnit Jupiter API for writing tests and extensions .
JUnit Jupiter test engine implementation; only required at runtime.
Support for parameterized tests in JUnit Jupiter.
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.
Group ID : org.junit.vintage
Artifact ID :
JUnit Vintage test engine implementation that allows one to run vintage JUnit tests on the JUnit Platform. Vintage tests include those written using JUnit 3 or JUnit 4 APIs or tests written using testing frameworks built on those APIs.
The Bill of Materials POM provided under the following Maven coordinates can be used to ease dependency management when referencing multiple of the above artifacts using Maven or Gradle .
Group ID : org.junit
Artifact ID : junit-bom
Most of the above artifacts have a dependency in their published Maven POMs on the following @API Guardian JAR.
Group ID : org.apiguardian
Artifact ID : apiguardian-api
Version : 1.1.2
In addition, most of the above artifacts have a direct or transitive dependency on the following OpenTest4J JAR.
Group ID : org.opentest4j
Artifact ID : opentest4j
Version : 1.3.0

IMAGES
VIDEO
COMMENTS
Are you looking to enhance your writing skills and master the intricacies of the English language? Look no further than online English grammar classes. In today’s digital age, learning has become more accessible than ever before.
There are 29 shingles in a standard bundle of three-tab roofing. Each shingle is 12 inches by 36 inches. It takes three bundles to make a square, which in roofing is 100 square feet.
There are exactly 1,000 $100 bills in a bundle. According to Federal Reserve Bank Services, a bundle is comprised of 10 currency straps of 100 bills each for all bills greater than $1. A currency strap of $100 bills is worth $10,000 and a 1...
I have configured jacoco plugin as follows. And my project structure as below. There is a parent pom and two modules as core and tests. core
Write better code with AI · Code review. Manage code changes · Issues. Plan ... bundle 'kapua-qa' with 0 classes. The text was updated
... bundle 'selenium' with 0 classes" / but with this command : java -jar jacococli.jar report jacoco.exec --classfiles myapp.jar --html html I
We rely on other people's code in our own work. Every day. It might be the language you're writing ... 0) { return true; } else { char firstChar =
New bundle org.jacoco.agent that provides the Java agent as a resource (Trac #50)
[WARNING] Classes in bundle 'KCAM :: 1.1.1-SNAPSHOT' do no match ... let me know what is the cause of getting zero coverage using jacoco plugin.
<limit counter="CLASS" value="MISSEDCOUNT" maximum="0"/>; </rule>; </check>.
0 or a combination of Parcelable.PARCELABLE_WRITE_RETURN_VALUE , and android.os
writing a regular function. 9.10. Generator Expressions¶. Some
<maximum>0</maximum> ... Each rule can be applied to an element type i.e., BUNDLE, PACKAGE, CLASS, SOURCEFILE , and METHOD using the element field
[ 0 tests aborted ] [ 5 tests successful ] [ 0 tests failed ]. You can