Junit5 introduction and common test notes

Junit5 introduction and common test notes

Spring boot has introduced JUnit 5 as the default library for unit testing since version 2.2.0. However, starting with versions above 2.4, the default dependency on Vintage (that is, modules compatible with JUnit 4 and JUnit 3) has been removed. If we need to be compatible with JUnit 4, we need to manually add JUnit 4 dependencies.

Next, let's introduce JUnit 5 and its common test annotations.

1. Introduction to Junit5

Junit5 is very different from the previous version, mainly composed of several different modules of three different subprojects. Here's a formula:

Junit5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

  • JUnit platform: JUnit platform is the basis for starting the test framework on the JVM. It supports not only JUnit's self-made test engine, but also other test engines.
  • JUnit Jupiter: JUnit Jupiter provides a new programming model for JUnit 5 and is the core of JUnit 5's new features. A test engine is included internally to run on the JUnit Platform.
  • JUnit Vintage: since JUnit has been developed for many years, in order to take care of old projects, JUnit Vintage provides a test engine compatible with JUnit 4 and JUnit 3.

To introduce JUnit 5 dependencies, we just need to import its starter (scenario).

<!--test-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

If we use springboot 2.4 and later versions to be compatible with Junit4 and Junit3, we have to add another dependency as follows:

<!--SpringBoot2.4 Start, compatible Junit4 Manual import required Vintage-->
<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

After integrating Junit5 with SpringBoot:
1. Write the test method: just use the @ test tag (note that the path of the @ test package is org.junit.jupiter.api.Test)
2. Junit class has the functions of Spring and Java, and can be automatically injected using @ Autowired and @ Resource.
3. For some test methods that need to be rolled back, we can add @ Transactional annotation to make the test method roll back automatically after execution.

2. Junit5 common test notes

annotationdescribe
@TestThe presentation method is a test method. Unlike Junit4, it cannot declare any properties
@ParameterizedTestThe representation method is parametric testing
@RepeatedTestThe representation method is repeatable
@DisplayNameSet the presentation name for the test class or method
@BeforeEachIndicates that it is executed before each unit test (several tests are executed several times)
@AfterEachIndicates that it is executed after each unit test (several tests are executed several times)
@BeforeAllMeans to execute before all unit tests (no matter how many tests are executed only once)
@AfterAllIndicates that it is executed after all unit tests (no matter how many tests are executed, it is only executed once)
@TagRepresents the unit test category, similar to Junit4's @ Categories
@DisabledIndicates that the test class or test method is not executed, similar to @ Ignore in Junit4
@TimeoutIndicates that the test method will return an error if it exceeds the specified time
@ExtendWithProvide an extension class reference for a test class or test method

1. DispalyName annotation:
Case: name the test class and method.

package com.example.boot;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@DisplayName("Just a test class with a name")
public class MyTest {

    @DisplayName("This is a method with a name")
    @Test
    public void testDisplayName(){
        System.out.println("test DisplayName");
    }
}

result:

2. BeforeEach and AfterEach annotations
Case: output a sentence before and after each test method.

package com.example.boot;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@DisplayName("Just a test class with a name")
public class MyTest {

    @DisplayName("This is a method with a name")
    @Test
    public void testDisplayName(){
        System.out.println("test DisplayName");
    }

    @BeforeEach
    public void testBeforeEach(){
        System.out.println("BeforeEach-------------");
    }
    
    @AfterEach
    public void testAfterEach(){
        System.out.println("AfterEach--------------");
    }
}

result:

3. BeforeAll and AfterAll annotations
Note: BeforeAll and AfterAll are executed before all test methods are executed, which means that they are only executed once in total. Therefore, the direct methods using BeforeAll and AfterAll are either static or have to add the rollback annotation @ Transactional. Otherwise, an error will be reported.
A class that runs the following methods, that is, executes all test methods.

package com.example.boot;

import org.junit.jupiter.api.*;

@DisplayName("Just a test class with a name")
public class MyTest {

    @DisplayName("This is a method with a name")
    @Test
    public void testDisplayName(){
        System.out.println("test DisplayName");
    }
    
    @DisplayName("This is the second method with a name")
    @Test
    public void testDisplayName_2(){
        System.out.println("Fell in love with naming the method");
    }

    @BeforeEach
    public void testBeforeEach(){
        System.out.println("BeforeEach-------------");
    }

    @AfterEach
    public void testAfterEach(){
        System.out.println("AfterEach--------------");
    }

    @BeforeAll
    public static void testBeforeAll(){
        System.out.println("BeforeAll---------------------");
    }

    @AfterAll
    public static void testAfterAll(){
        System.out.println("AfterAll----------------------");
    }
}

Results: (BeforeEach and AfterEach are executed before and after each test method, and BeforeAll and AfterAll are executed only once at the front and back)

4. @ Disable annotation
Now, we don't want to run the second test method, so we can add the @ Disable annotation to the second test method, so that when we run our test class, we won't run that test method.

Result: (also told us that the method has @ Disable annotation, which is humanized!!!)

5. @ TimeOut annotation
If the program runs for more than the specified time, it will automatically report an error.
The first parameter is a value and the second parameter is a unit. (there are days, hours, minutes, seconds, milliseconds, etc.)

@Timeout(value = 500,unit = TimeUnit.MILLISECONDS)
@Test
public void testTimeout() throws InterruptedException {
    Thread.sleep(600);
}

result:

Unit of the second parameter:

6. @ ExtendWith annotation
This annotation is great. If we do not use the @ SpringBootTest annotation, we cannot use our @ AutoWired annotation in this test class. The reason why it can be used is that the @ SpringBootTest annotation extends a series of annotations about Spring (of course, the above sentence @ bootstrap with is also useful):

7. @ RepeatedTest annotation*
@The RepeatedTest annotation repeats the test.

@RepeatedTest(3)
@Test
public void testRepeated(){
    System.out.println("Run!!!");
}

After a try, he seems to run once and then repeat it three times.
The results are as follows: (once above, three times below)

Tags: Java Spring Spring Boot unit testing

Posted by ClaytonBellmor on Mon, 20 Sep 2021 23:31:39 +0530