JUnit unit automation

1. What is Junit?

Junit is a framework for unit testing in Java. Using Junit allows us to complete unit testing quickly and efficiently.

  • Automated testing: JUnit provides the ability to automate testing. Developers can write test cases once and then run them repeatedly through simple commands or integrated into continuous integration tools, which greatly improves the efficiency of testing. Reduced repetitive testing workload.
  • Annotations and assertions: JUnit uses annotations to mark test methods and assertions to verify results, making test case writing more concise and intuitive, while reducing the need to manually write test code probability of error.

In the traditional mode, if we want to test the correctness of this code after writing it, we must create a new class, then create a main() method, and then write the test code. What if there is a lot of code that needs to be tested? Then either you will build many main() methods for testing, or write them all in one main() method. This will also greatly increase the complexity of testing and reduce programmers' testing enthusiasm. Junit can solve this problem very well, simplify unit testing, write a little and test a little. If a problem is found in the subsequent code writing, the cause of the problem can be traced quickly, reducing the difficulty of correcting regression errors.

2. Configure Junit environment

To configure Junit, you only need to import the relevant dependencies in the unit test. We are using Junit5 here. maven address: https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api/5.8.2

<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.8.2</version>
    <scope>test</scope>
</dependency>

Let's write a demo to test whether the import is successful:

import org.junit.jupiter.api.Test;
public class JunitTest {
    
    
    @Test
    void testDemo() {
    
    
        System.out.println("这是第一个单元测试!");
    }
}

1. Commonly used annotations

  • @TestAnnotations are used to mark test methods. JUnit will execute all methods marked with @Test annotation as test cases.

  • @DisabledAnnotations are used to mark a test method and disable it, which is useful when you don't want to execute a test method temporarily.

  • @BeforeAllAnnotations are used to mark methods that need to be executed only once before all test methods are executed. And the method modified by this annotation must be a static method. Usually used to initialize static resources.

  • @AfterAllAnnotations are used to mark methods that only need to be executed once after all test methods are executed. And the method modified by this annotation must be a static method. Usually used to release static resources.

  • @BeforeEachAnnotations are used to mark methods that need to be executed before each test method. Usually used to initialize the test environment.

  • @AfterEachAnnotations are used to mark methods that need to be executed after each test method. Usually used to clean up the test environment.

public class JunitTest {
    
    

    @BeforeAll
    static void setUp() {
    
    
        System.out.println("所有测试方法执行之前执行BeforeAll");
    }

    @AfterAll
    static void tearDown() {
    
    
        System.out.println("所有测试方法执行结束后执行AfterAll");
    }

    @BeforeEach
    void setUpEach() {
    
    
        System.out.println("在每个测试方法执行前执行BeforeEach");
    }

    @AfterEach
    void tearDownEach() {
    
    
        System.out.println("在每个测试方法执行之后执行AfterEach");
    }

    @Test
    void testDemo1() {
    
    
        System.out.println("testDemo1()");
    }

    @Test
    void testDemo2() {
    
    
        System.out.println("testDemo2()");
    }

    @Disabled
    void testDemo3() {
    
    
        System.out.println("testDemo3()");
    }
}

2, affirmation

In JUnit, assertions are tools used to verify whether test results meet expectations. The following are some commonly used JUnit assertion methods:

  • assertEquals(expected, actual): Verify that two values ​​are equal. Suitable for comparing basic data types or objects.
  • assertNotEquals(unexpected, actual): Verify whether two values ​​are not equal.
  • assertTrue(condition): Verify whether the condition is true.
  • assertFalse(condition): Verify whether the condition is false.
  • assertNull(object): Verify whether the object is null.
  • assertNotNull(object): Verify that the object is not null.
  • assertArrayEquals(expectedArray, resultArray): Verify whether two arrays are equal.
  • assertSame(expected, actual): Verify whether two references point to the same object.
  • assertNotSame(unexpected, actual): Verify whether two references point to different objects.
  • assertThrows(expectedException, executable): Verify whether the method threw the expected exception.

Here is a simple usage example:

public class JunitTest {
    
    

    @Test
    void testDemo1() {
    
    
        Assertions.assertEquals("aaa","aaa");
        Assertions.assertTrue(true);
    }

    @Test
    void testDemo2() {
    
    
        Assertions.assertTrue(false);
    }
}

3. Parameterization

Parameterized test cases can help us better manage test cases, separate test data from test cases, and realize test case reuse. JUnit 5 provides the @ParameterizedTest annotation to support parameterized testing. You need to import related dependencies before using it. maven warehouse address: https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params/5.8.2

@ParameterizedTestData sources need to be used to provide test data for parameterized testing. The following are some commonly used data sources and their usage:

(1) @ValueSource Annotation: Used to provide a single value of a basic type as a parameter, such as integer, string, Boolean, etc.

    @ParameterizedTest
    @ValueSource(ints = {
    
    1,2,3})
    void test(int num) {
    
    
        System.out.println(num);
    }

(2) @EnumSource Note: Used to provide enumeration types as parameters, and you can specify the included enumeration types.

    // 定义一个枚举
    enum Season {
    
    
        a,b,c

    }
    @ParameterizedTest
    @EnumSource(Season.class)
    void test2(Season season) {
    
    
        System.out.println(season);
    }

(3)@CsvSource Annotation: Allows you to directly define data in CSV format inline and pass it to the test method as a parameter.

    @ParameterizedTest
    @CsvSource({
    
    
            "apple, 1",
            "banana, 2",
            "orange, 3"
    })
    void testWithCsvSource(String fruit, int count) {
    
    
        // 测试代码
        System.out.println("fruit = "+fruit+", count = "+count);
    }

(4)@CsvFileSource Annotation: Allows you to read data from an external CSV file and pass it as a parameter to the test method.

    @ParameterizedTest
    @CsvFileSource(resources = "test-data.csv", numLinesToSkip = 1)
    void testWithCsvFileSource(String name, String gender ,int age) {
    
    
        // 测试代码
        System.out.println("name = "+name+", gender = "+gender+", age = "+age);
    }

Note: Usually, the first line of the CSV file will contain column headers or field names, describing the meaning of each column of data. When using @CsvFileSource for parameterized testing, using numLinesToSkip = 1 to skip the first line avoids passing column headers as test data to the test method.

(5)@MethodSource Annotation: Used to specify a method as a data source. The method must return a Stream, Iterable, Iterator or array.

    public static Stream<Arguments> generateData() {
    
    
        return Stream.of(Arguments.arguments("张三",18,"男"),
                Arguments.arguments("张三",19,"女"),
                Arguments.arguments("李四",20,"女"));
    }
    @ParameterizedTest
    @MethodSource("generateData")
    void testWithSimpleMethodSource(String name,int age,String gender) {
    
    
        // 测试代码
        System.out.println("name = "+name+", age = "+age+", gender = "+gender);
    }

4. Execution order of test cases

In JUnit, the execution order of test methods is not guaranteed. It is not executed from top to bottom as we think. As an example to disprove this, we can write a Demo to demonstrate:

But in actual testing, we need to complete multiple consecutive steps of testing, and we need to specify the order in which test cases are executed. The @TestMethodOrder annotation in JUnit 5 can be used to specify the execution order of test methods.

The @TestMethodOrder annotation can be used with a custom sequencer that implements the MethodOrderer interface to execute test methods according to a specific ordering strategy. The main test method sequencers provided by JUnit 5:

  • MethodNameOrderer: Execute test methods in dictionary order of method names.
  • Random: Randomly execute test methods.
  • OrderAnnotation: Execute test methods according to the order specified in the @Order annotation.

MethodNameOrderer test

Random test

OrderAnnotation test

5. Test suite

When we have multiple test cases in a class, it is impossible for us to run them one by one, which will be very time-consuming. At this time, we need a test suite to specify the class or specify the package name to run all tests under the class or package. Example. In Junit, you can use @Suite to mark the test suite, and you need to import dependencies when using it. maven address: https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite/1.9.1

In addition, using suite requires introducing the engine dependency. maven address: https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine/5.8.2

(1) Specify Class to execute test cases

Usage notes:@SelectClasses({指定类, 指定类, 指定类})

(2) Specify the package to execute the test case

Usage notes:@SelectPackages(value = {"包1", "包2","..."})

PS: If you use the package name to specify the running scope, then all test classes under the package need to be named with Test or Tests Ending (T must be capitalized);

Guess you like

Origin blog.csdn.net/LEE180501/article/details/134356102