Similar to MethodOrderer, JUnit 5 allows creating custom ClassOrderer implementations for controlling test class execution order. This is useful for organizing test suites, managing dependencies between test classes, or implementing complex test orchestration logic.
Implementing ClassOrderer
Custom ClassOrderers implement the ClassOrderer interface and override the orderClasses method. This method receives a ClassOrdererContext containing test class descriptors and returns an ordered list of classes.
ClassOrderer interface
package org.junit.jupiter.api;
.....
public interface ClassOrderer {
void orderClasses(ClassOrdererContext context);
...
}
Definition of ClassOrdererContextVersion: 6.0.0 package org.junit.jupiter.api;
@API(status = STABLE, since = "5.10")
public interface ClassOrdererContext {
List<? extends ClassDescriptor> getClassDescriptors(); 1
Optional<String> getConfigurationParameter(String key); 2
}
Example
Implementing custom ClassOrderer
Following is a custom ClassOrderer that sorts classes by their simple name's length.
package com.logicbig.example;
import org.junit.jupiter.api.ClassDescriptor;
import org.junit.jupiter.api.ClassOrderer;
import org.junit.jupiter.api.ClassOrdererContext;
import java.util.Comparator;
public class OrderAnnotationClassOrderer implements ClassOrderer {
@Override
public void orderClasses(ClassOrdererContext context) {
context.getClassDescriptors().sort(
Comparator.comparingInt(
(ClassDescriptor o) ->
getSimpleClassLength(o))
);
}
private static int getSimpleClassLength(ClassDescriptor o) {
return o.getTestClass()
.getSimpleName().length();
}
}
Test classes
package com.logicbig.example;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestClassOrder;
import static org.junit.jupiter.api.Assertions.assertTrue;
@TestClassOrder(OrderAnnotationClassOrderer.class)
class CustomClassOrdererTest {
@Nested
class ParserTestClass {
@Test
void testB() {
assertTrue(true);
}
}
@Nested
class CalcClass {
@Test
void testA() {
assertTrue(true);
}
}
@Nested
class IntegrationTestClass {
@Test
void testC() {
assertTrue(true);
}
}
}
Output$ mvn test -Dtest=CustomClassOrdererTest [INFO] Scanning for projects... [INFO] [INFO] --< com.logicbig.example:junit-5-custom-class-orderer-implementation >-- [INFO] Building junit-5-custom-class-orderer-implementation 1.0-SNAPSHOT [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- resources:3.3.1:resources (default-resources) @ junit-5-custom-class-orderer-implementation --- [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-ordering\junit-5-custom-class-orderer-implementation\src\main\resources [INFO] [INFO] --- compiler:3.11.0:compile (default-compile) @ junit-5-custom-class-orderer-implementation --- [INFO] No sources to compile [INFO] [INFO] --- resources:3.3.1:testResources (default-testResources) @ junit-5-custom-class-orderer-implementation --- [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-ordering\junit-5-custom-class-orderer-implementation\src\test\resources [INFO] [INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ junit-5-custom-class-orderer-implementation --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- surefire:3.5.0:test (default-test) @ junit-5-custom-class-orderer-implementation --- [INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] +--.--com.logicbig.example.CustomClassOrdererTest$CalcClass - 0.158 ss [INFO] | | '-- [OK] testA - 0.087 ss [INFO] +--.--com.logicbig.example.CustomClassOrdererTest$ParserTestClass - 0.158 ss [INFO] | | '-- [OK] testB - 0.027 ss [INFO] +-----com.logicbig.example.CustomClassOrdererTest$IntegrationTestClass - 0.158 ss [INFO] | '-- [OK] testC - 0.003 ss [INFO] [INFO] Results: [INFO] [INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 4.935 s [INFO] Finished at: 2025-12-22T17:18:01+08:00 [INFO] ------------------------------------------------------------------------
As shown in the test execution output above, the custom ClassOrderer successfully sorted the nested test classes in ascending order based on the length of their simple names. The classes were executed in this sequence: CalcClass (8 characters), ParserTestClass (15 characters), and IntegrationTestClass (21 characters). This demonstrates how a custom ClassOrderer can control the execution order of nested test classes according to specific sorting criteria, providing flexibility in test organization and execution flow.
Example ProjectDependencies and Technologies Used: - junit-jupiter-engine 6.0.1 (Module "junit-jupiter-engine" of JUnit)
Version Compatibility: 5.8.0 - 6.0.1 Version compatibilities of junit-jupiter-engine with this example:
- 5.8.0
- 5.8.1
- 5.8.2
- 5.9.0
- 5.9.1
- 5.9.2
- 5.9.3
- 5.10.0
- 5.10.1
- 5.10.2
- 5.10.3
- 5.10.4
- 5.10.5
- 5.11.0
- 5.11.1
- 5.11.2
- 5.11.3
- 5.11.4
- 5.12.0
- 5.12.1
- 5.12.2
- 5.13.0
- 5.13.1
- 5.13.2
- 5.13.3
- 5.13.4
- 5.14.0
- 5.14.1
- 6.0.0
- 6.0.1
Versions in green have been tested.
- JDK 25
- Maven 3.9.11
|