2. JUnit 5中的测试方法排序

在JUnit 5中,我们可以使用@TestMethodOrder注解来控制测试的执行顺序。支持三种内置排序方式:

  • 字母数字顺序
  • @Order注解
  • 随机顺序

2.1. 使用字母数字顺序

JUnit 5提供内置的MethodOrderer实现,可按字母数字顺序运行测试。例如MethodOrderer.MethodName会根据方法名和形参列表排序:

@TestMethodOrder(MethodOrderer.MethodName.class)
public class AlphanumericOrderUnitTest {
    private static StringBuilder output = new StringBuilder("");
    
    @Test
    void myATest() {
        output.append("A");
    }
    
    @Test
    void myBTest() {
        output.append("B");        
    }
    
    @Test
    void myaTest() {
        output.append("a");
    }
 
    @AfterAll
    public static void assertOutput() {
        assertEquals("ABa", output.toString());
    }
}

⚠️ 注意:MethodOrderer.Alphanumeric已废弃,将在6.0版本移除。

2.2. 使用@Order注解

通过@Order注解强制按指定顺序执行测试:

@TestMethodOrder(OrderAnnotation.class)
public class OrderAnnotationUnitTest {
    private static StringBuilder output = new StringBuilder("");
    
    @Test
    @Order(1)    
    void firstTest() {
        output.append("a");
    }
    
    @Test
    @Order(2)    
    void secondTest() {
        output.append("b");
    }
 
    @Test
    @Order(3)    
    void thirdTest() {
        output.append("c");
    }
 
    @AfterAll
    public static void assertOutput() {
        assertEquals("abc", output.toString());
    }
}

2.3. 使用随机顺序

使用MethodOrderer.Random实现伪随机排序:

@TestMethodOrder(MethodOrderer.Random.class)
public class RandomOrderUnitTest {

    private static StringBuilder output = new StringBuilder("");

    @Test
    void myATest() {
        output.append("A");
    }

    @Test
    void myBTest() {
        output.append("B");
    }

    @Test
    void myCTest() {
        output.append("C");
    }

    @AfterAll
    public static void assertOutput() {
        assertEquals("ACB", output.toString());
    }
}

⚠️ 默认使用System.nanoTime()作为随机种子,可能导致重复运行时顺序不一致。可通过配置固定种子解决:

junit.jupiter.execution.order.random.seed=100

2.4. 使用自定义顺序

实现MethodOrderer接口创建自定义排序器:

public class CustomOrder implements MethodOrderer {
    @Override
    public void orderMethods(MethodOrdererContext context) {
        context.getMethodDescriptors().sort(
         (MethodDescriptor m1, MethodDescriptor m2)->
           m1.getMethod().getName().compareToIgnoreCase(m2.getMethod().getName()));
    }
}

使用方式:

@TestMethodOrder(CustomOrder.class)
public class CustomOrderUnitTest {
    // 测试方法...
 
    @AfterAll
    public static void assertOutput() {
        assertEquals("AaB", output.toString());
    }
}

2.5. 设置默认排序

通过junit-platform.properties配置全局默认排序器:

junit.jupiter.testmethod.order.default = org.junit.jupiter.api.MethodOrderer$DisplayName

✅ 此配置将应用于**所有未使用@TestMethodOrder**的测试类。

3. JUnit 4中的测试方法排序

3.1. 使用MethodSorters.DEFAULT

默认策略基于哈希值排序,冲突时按字典序:

@FixMethodOrder(MethodSorters.DEFAULT)
public class DefaultOrderOfExecutionTest {
    private static StringBuilder output = new StringBuilder("");

    @Test
    public void secondTest() {
        output.append("b");
    }

    @Test
    public void thirdTest() {
        output.append("c");
    }

    @Test
    public void firstTest() {
        output.append("a");
    }

    @AfterClass
    public static void assertOutput() {
        assertEquals(output.toString(), "cab");
    }
}

3.2. 使用MethodSorters.JVM

使用JVM自然排序,每次运行顺序可能不同

@FixMethodOrder(MethodSorters.JVM)
public class JVMOrderOfExecutionTest {    
    // 测试方法同上
}

3.3. 使用MethodSorters.NAME_ASCENDING

按方法名字典序排序:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class NameAscendingOrderOfExecutionTest {
    // 测试方法同上
    
    @AfterClass
    public static void assertOutput() {
        assertEquals(output.toString(), "abc");
    }
}

4. 使用@TestClassOrder控制测试类顺序

JUnit 5提供ClassOrderer接口支持测试类排序,支持以下方式:

  • ClassName - 按类名排序
  • DisplayName - 按显示名排序
  • OrderAnnotation - 按@Order注解排序
  • Random - 随机排序
  • 自定义排序

4.1. 使用ClassName

按类名字母顺序执行:

@TestClassOrder(ClassOrderer.ClassName.class)
public class ClassNameOrderUnitTest {
    @Nested
    class C extends TestC {}

    @Nested
    class B extends TestB {}

    @Nested
    class A extends TestA {}
}

输出:

Running TestA
Running TestB
Running TestC

4.2. 使用DisplayName

按显示名排序(未设置时回退到类名):

@TestClassOrder(ClassOrderer.DisplayName.class)
public class DisplayNameOrderUnitTest {
    @Nested
    @DisplayName("Class C")
    class Z extends TestC {}

    @Nested
    @DisplayName("Class B")
    class A extends TestA {}

    @Nested
    @DisplayName("Class A")
    class B extends TestB {}
}

输出:

Running TestB
Running TestA
Running TestC

4.3. 使用OrderAnnotation

通过@Order指定优先级:

@TestClassOrder(ClassOrderer.OrderAnnotation.class)
public class OrderAnnotationUnitTest {
    @Nested
    @Order(3)
    class A extends TestA {}

    @Nested
    @Order(1)
    class B extends TestB {}

    @Nested
    @Order(2)
    class C extends TestC {}
}

输出:

Running TestB
Running TestC
Running TestA

4.4. 随机顺序

使用随机排序检测测试依赖:

@TestClassOrder(ClassOrderer.Random.class)
public class RandomOrderUnitTest {
    @Nested
    class C extends TestC {}

    @Nested
    class B extends TestB {}

    @Nested
    class A extends TestA {}
}

运行1输出:

Running TestA
Running TestC
Running TestB

运行2输出:

Running TestC
Running TestA
Running TestB

4.5. 使用自定义顺序

实现ClassOrderer接口创建自定义排序器:

public class CustomClassOrderer implements ClassOrderer {
    @Override
    public void orderClasses(ClassOrdererContext context) {
        context.getClassDescriptors().sort(
            Comparator.comparingInt(descriptor ->
                descriptor.getTestClass().getSimpleName().length()
            )
        );
    }
}

使用方式:

@TestClassOrder(CustomClassOrderer.class)
public class CustomOrderUnitTest {
    @Nested
    class Longest extends TestA {}

    @Nested
    class Middle extends TestB {}

    @Nested
    class Short extends TestC {}
}

输出(按类名长度排序):

Running TestC
Running TestB
Running TestA

5. 总结

本文系统介绍了JUnit中控制测试执行顺序的各种方法:

  • JUnit 5支持@TestMethodOrder@TestClassOrder注解
  • 提供字母数字、注解、随机等多种内置排序策略
  • 可通过实现接口创建自定义排序逻辑
  • JUnit 4使用@FixMethodOrder实现类似功能

合理使用测试排序能帮助发现隐藏的测试依赖问题,提升测试可靠性。但需注意过度依赖执行顺序可能掩盖测试设计缺陷。


原始标题:The Order of Tests in JUnit | Baeldung