Summarize the relationship among Junit4 Junit5 and Jupiter

  • 2021-10-13 07:29:50
  • OfStack

Junit5

At present, the most popular unit testing framework in Java field-JUnit

The latest version of Junit, JUnit5, was released in 2017.

Junit 5 = Junit Platform + Junit Jupiter + Junit Vintage

Junit Platform: Junit Platform is the basis for starting the test framework on JVM, which not only supports the self-made test engine of Junit, but also can access other test engines.

Junit Jupiter: Junit Jupiter provides a new programming model for JUnit5 and is at the heart of the new features of JUnit5. It contains a test engine to run on 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 JUnit4. x and Junit3. x.

Dependency

Junit4


<dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>

Currently dependency will introduce packages for junit: 4.12 and hamcrest-core: 1.3

Junit vintage engine


    <dependency>
        <groupId>org.junit.vintage</groupId>
        <artifactId>junit-vintage-engine</artifactId>
        <version>5.6.2</version>
        <scope>test</scope>
    </dependency>

At present, dependency will introduce unit: 4.13, apiguardian-api: 1.1. 0, hamcrest-core: 1.3, junit-platform-commons: 1.6. 2.
Packages for junit-platform-engine: 1.6. 2, junit-vintage-engine: 5.6. 2, opentest4j: 1.2. 0

Jupiter


 <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.6.2</version>
        <scope>test</scope>
    </dependency>

At present, dependency will introduce packages of apiguardian-api: 1.1. 0, junit-Jupiter-api: 5.6. 2, junit-platform-commons: 1.6. 2, opentest4j: 1.2. 0

Annotation Difference between Junit4 and Junit5

Junit5 Junit4 说明
@Test @Test 被注解的方法是1个测试方法。与 JUnit 4 相同。
@BeforeAll @BeforeClass 被注解的(静态)方法将在当前类中的所有 @Test 方法前执行1次。
@BeforeEach @Before 被注解的方法将在当前类中的每个 @Test 方法前执行。
@AfterEach @After 被注解的方法将在当前类中的每个 @Test 方法后执行。
@AfterAll @AfterClass 被注解的(静态)方法将在当前类中的所有 @Test 方法后执行1次。
@Disabled @Ignore 被注解的方法不会执行(将被跳过),但会报告为已执行

@ Test in Junit4 is import org. junit. Test;

The @ Test in Jupiter is import org. junit. jupiter. api. Test;

Assertion

There are standard assertions in Junit4 and Junit5

断言方法 说明
assertEquals(expected, actual) 如果 expected 不等于 actual ,则断言失败。
assertFalse(booleanExpression) 如果 booleanExpression 不是 false ,则断言失败。
assertNull(actual) 如果 actual 不是 null ,则断言失败。
assertNotNull(actual) 如果 actual 是 null ,则断言失败。
assertTrue(booleanExpression) 如果 booleanExpression 不是 true ,则断言失败。

If any assertion in Junit4 fails, the test will fail at that location, meaning that no other assertions will be executed. For example, should_test_every_test in StudentTest.


    @Test
    public void should_test_every_test() {
        //given when
        int expected = 6;
        int actual = 10 - 4;
        Object nullValue = null;

        //then
        assertEquals(expected, actual);
        assertFalse(true);
        assertNull(nullValue);
        assertTrue(false);
    }

What if you want all assertions to be executed, even if one or more assertions fail?

You can use the aseertAll method provided in Jupiter


    @Test
    @DisplayName("test assertAll")
    void should_test_every_test() {
        //given when
        int expected = 4;
        int actual = 2 + 2;
        Object nullValue = null;

        //then
        assertAll(
                "Assert All of these",
                () -> assertEquals(expected, actual),
                () -> assertFalse(nullValue == null),
                () -> assertNull(nullValue),
                () -> assertNotNull("Hello Word!"),
                () -> assertTrue(nullValue != null));
    }

@DisplayName

You can add @ DisplayName annotations to classes and methods. This name is used when generating reports, which makes it easier to describe the purpose of tests and track failures

After running the unit test, click the following location to generate the html report

The unit test report generated by Student is Test Results-StudentTest. html

The unit test report generated by StudentJupiterTest is Test Results-StudentJupiterTest. html

Check anomaly

Junit4 provides @ Test (expected = Exception. class) to verify exceptions, but the disadvantage of this approach is that when two different services throw the same traffic exception,
However, only when message is different, it cannot be accurately verified.


    @Test(expected = BusinessException.class)
    public void should_throw_business_exception_when_student_name_length_more_than_10() {
        //given when
        StudentCommand.builder()
                      .name(RandomStringUtils.randomAlphanumeric(11))
                      .build();
    }
    
    @Test(expected = BusinessException.class)
    public void should_throw_business_exception_when_student_description_length_more_than_20() {
        //given when
        StudentCommand.builder()
                .name(RandomStringUtils.randomAlphanumeric(9))
                .description(RandomStringUtils.randomAlphanumeric(21))
                .build();
    }

Of course, it is also possible to judge message by catching exceptions, but this method is not very elegant.


    @Test
    public void should_validate_message_when_student_name_length_more_than_10() {
        //given when
        try {
            StudentCommand.builder()
                          .name(RandomStringUtils.randomAlphanumeric(11))
                          .build();
        } catch (BusinessException e) {
            assertEquals(e.getMessage(), "The length of student name exceed 10 chars.");
        }
    }

Jupiter provides a new verification method, Assertions. assertThrows, and in version 4.13 of Junit, Asserts. assertThrows also provides similar functions


    @Test
    @DisplayName("It tests the length of student name should less than 10 chars")
    void should_throw_business_exception_when_student_name_length_more_than_10() {
        //given when
        BusinessException businessException = Assertions.assertThrows(BusinessException.class, this::buildStudentName);

        //then
        assertEquals(businessException.getMessage(), "The length of student name exceed 10 chars.");
    }

    private void buildStudentName() {
        StudentCommand.builder()
                .name(RandomStringUtils.randomAlphanumeric(11))
                .build();
    }

    @Test
    @DisplayName("It tests the length of student description should less than 20 chars")
    void should_throw_business_exception_when_student_description_length_more_than_20() {
        //given when
        BusinessException businessException = Assertions.assertThrows(BusinessException.class, this::buildStudentDescription);

        //then
        assertEquals(businessException.getMessage(), "The length of student name exceed 20 chars.");
    }

    private void buildStudentDescription() {
        StudentCommand.builder()
                .description(RandomStringUtils.randomAlphanumeric(21))
                .build();
    }

Related articles: