Tags:

Thực thi unit test có thứ tự JUnit 5

Trong JUnit 5, mặc định các test method sẽ được thực thi theo thứ tự được xác định bởi thuật toán mà JUnit 5 đã xây dựng sẵn.

Mặc dù 1 unit test thông thường không nên ảnh hưởng bởi thứ tự thực thi, nhưng trong 1 số trường hợp nhất định chúng ta sẽ cần. Ví dụ như chúng ta viết integration test thì thứ tự thực thi của các test method rất quan trọng quyết định đến kết quả cuối cùng của integration test.

Note: Thực thi unit test có thứ tự thường sẽ kết hợp với @TestInstance(LifeCylcle.PER_CLASS). 

@TestMethodOrder annotation

Chúng ta có thể sử dụng @TestMethodOrder để điều khiển thứ tự thực thi của các unit test.

@Order annotation

Sử dụng @Order annotation để chỉ định thứ tự cho từng method cụ thể.

package order;

import org.junit.jupiter.api.*;

import static org.junit.jupiter.api.Assertions.assertEquals;

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class OrderAnnotationExample {
    private static StringBuilder output = new StringBuilder("");

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

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

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

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

Thứ tự thực thi sẽ là firstTest() đầu tiên, đến secondTest(), thirdTest(), assertOutput().

Alphanumeric

Alphanumeric class sắp xếp và thực thi các test method theo tên, lưu ý là nó phân biệt chữ hoa và chữ thường nên các ký tự hoa sẽ ưu tiên chạy trước ký tự thường.

package order;


import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import static org.junit.jupiter.api.Assertions.assertEquals;

@TestMethodOrder(MethodOrderer.Alphanumeric.class)
public class AlphanumericExample {
    private static StringBuilder output = new StringBuilder("");

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

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

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

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

Các unit test sẽ thực thi theo thứ tự: myATest()myBTest() and finally myaTest().

Random

Sử dụng Random class để thực thi ngẫu nhiên các test method ở mỗi lần chạy, như vậy thứ tự thực thi có thể khác nhau ở mỗi lần chạy.

package order;

import org.junit.jupiter.api.*;

import static org.junit.jupiter.api.Assertions.assertEquals;

@TestMethodOrder(MethodOrderer.Random.class)
public class RandomExample {
    @Test
    void testZ() {
        assertEquals(2, 1 + 1);
    }

    @Test
    void testA() {
        assertEquals(2, 1 + 1);
    }

    @Test
    void testY() {
        assertEquals(2, 1 + 1);
    }

    @Test
    void testE() {
        assertEquals(2, 1 + 1);
    }

    @Test
    void testB() {
        assertEquals(2, 1 + 1);
    }


}

Output

# Run 1
testA()
test()
testE()
testY()
test()
# Run 2
testY()
testE()
testA()
testA()
testB()
# Run 3
testA()
testB()
testY()
testE()

Custom Order

Nếu nhu cầu của các bạn cao hơn mà các annotation được xây dựng không đáp ứng, chúng ta có thể tuỳ biến cách sắp xếp và thực thi các unit test bằng cách implement MethodOrderer interface.

Ví dụ mình muốn sắp xếp các unit test theo tên không phân biệt hoa thường. Mình sẽ tạo 1 class CustomOrder như sau:

package order;

import org.junit.jupiter.api.MethodDescriptor;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.MethodOrdererContext;

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()));
    }
}
package order;


import org.junit.jupiter.api.*;

import static org.junit.jupiter.api.Assertions.assertEquals;

@TestMethodOrder(CustomOrder.class)
public class CustomOrderExample {
    private static StringBuilder output = new StringBuilder("");

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

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

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

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

}

Note: rằng CustomOrder không được là nested class.

Thứ tự thực thi là: myATest()myBTest() and finally myaTest()

Tóm lược

Trong bài viết này chúng ta đã tìm hiểu xong về cách thực thi các unit test với thứ tự do chúng ta tự định nghĩa hoặc sử dụng các class được JUnit xây dựng sẵn. Nó sẽ có ích khi các chúng ta viết integration test, hoặc 1 số mục đích cụ thể.

Nếu các bạn gặp khó khăn trong quá trình thực nghiệm, có thể checkout source mình đã soạn sẵn tại github repository.

Nguồn tham khảo:

https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-execution-order

https://mkyong.com/junit5/junit-5-test-execution-order/

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x