Skip to content

4.编写测试

标准测试 @Test

使用 @Test 注解标记成标准的测试用例

import org.junit.jupiter.api.Test;

public class BasicTests {

    @Test
    void basicTest(){
        System.out.println("这是一条测试用例");
    }
}

前置处理

  • @BeforeAll
  • @BeforeEach

使用@BeforeAll可以让被注解的方法,在当前类的所有@Test@RepeatedTest@ParameterizedTest@TestFactory方法之前执行。

使用@BeforeEach可以让被注解的方法,在当前类的每个@Test@RepeatedTest@ParameterizedTest@TestFactory方法之前执行。

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;


public class SetupTests {

    @BeforeAll
    static void beforeAll(){
        System.out.println("这是BeforeAll");
    }

    @BeforeEach
    void beforeEach(){
        System.out.println("这是BeforeEach");
    }

    @Test
    void basicTestOne(){
        System.out.println("第一条测试用例正在执行");
    }

    @Test
    void basicTestTwo(){
        System.out.println("第二条测试用例正在执行");
    }
}
运行测试类后会输出:
这是BeforeAll
这是BeforeEach
第一条测试用例正在执行
这是BeforeEach
第二条测试用例正在执行

后置处理

  • @AfterAll
  • @AfterEach

使用@AfterAll可以让被注解的方法,在当前类的所有@Test@RepeatedTest@ParameterizedTest@TestFactory方法之后执行。

使用@AfterEach可以让被注解的方法,在当前类的每个@Test@RepeatedTest@ParameterizedTest@TestFactory方法之后执行。

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;


public class TeardownTests {

    @AfterAll
    static void afterAll(){
        System.out.println("这是AfterAll");
    }

    @AfterEach
    void afterEach(){
        System.out.println("这是AfterEach");
    }

    @Test
    void basicTestOne(){
        System.out.println("第一条测试用例正在执行");
    }

    @Test
    void basicTestTwo(){
        System.out.println("第二条测试用例正在执行");
    }
}
运行测试类后会输出:
第一条测试用例正在执行
这是AfterEach
第二条测试用例正在执行
这是AfterEach
这是AfterAll

断言

内置断言

所有JUnit Jupiter断言都是org.junit.jupiter.api.Assertions类中的静态方法。

JUnit5提供了许多JUnit4已有的断言方法,并增加了一些适合与Java 8 lambda一起使用的断言方法。

  • assertTrue
  • assertEquals
  • assertAll
  • assertNotNull
  • assertThrows
  • assertTimeout
  • assertTimeoutPreemptively

assertTrue()

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class AssertEqualsTests {

    @Test
    void assertTrueTest(){
        assertTrue(1+1 >= 2);
    }
}

assertEquals()

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

public class AssertEqualsTests {

    @Test
    void assertEqualsTest(){
        assertEquals(2, 1+1);
        assertEquals(2, 1+1, "备注");
    }
}

assertAll() 分组断言。当全部断言为真时则为真,否则为假。

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;


public class AssertAllTests {
    @Test
    void assertAllTest(){
        assertAll("person",
                () -> assertEquals(2, 1+1),
                () -> assertTrue(1+1>=2)
        );
    }
}

assertNotNull() 非空断言

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;

public class AssertNotNullTests {
    @Test
    void assertNotNullTest(){
        assertNotNull("断言非空");
    }
}

assertThrows() 异常断言

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

public class AssertThrowsTests {

    @Test
    void assertThrowsTest(){
        // 断言异常
        Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
            throw new IllegalArgumentException("抛出异常");
        });

        assertEquals("抛出异常", exception.getMessage());
    }
}

assertTimeout() 超时断言。

设置一个限定时长,如果测试方法耗费的时间超过限定时长,则会在用例的所有操作结束后才判定用例执行失败。

import org.junit.jupiter.api.Test;
import static java.lang.Thread.sleep;
import static java.time.Duration.ofSeconds;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTimeout;

public class AssertTimeoutTests {

    @Test
    void assertTimeoutTest(){
        // 断言超时(5秒后执行结束)
        assertTimeout(ofSeconds(2), () -> {
            sleep(5000);
        });
    }

    @Test
    void assertTimeoutWithResult(){
        // 断言超时(有返回)
        String result = assertTimeout(ofSeconds(2), () -> {
            return "结果";
        });

        assertEquals("结果", result);
    }
}

assertTimeoutPreemptively() 先发制人的超时断言

设置一个限定时长,如果测试方法耗费的时间一旦超过限定时长,则会立即判定用例执行失败。

import org.junit.jupiter.api.Test;
import static java.time.Duration.ofSeconds;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;

public class AssertTimeoutPreemptivelyTests {

    @Test
    void testAssertTimeoutPreemptivelyTest(){
        // 断言超时(2秒后立即执行结束)
        assertTimeoutPreemptively(ofSeconds(2), () -> {
            Thread.sleep(5000);
        });
    }
}

注意:assertTimeout()assertTimeoutPreemptively()的区别在于是否会等待已超时的用例执行完毕。assertTimeout()会等而assertTimeoutPreemptively()不会等待,到点立即结束。

第三方断言

虽然JUnit Jupiter提供的断言功能足以满足许多测试场景的需要,但是有时需要更强大和附加功能,例如匹配器。在这种情况下,JUnit小组推荐使用AssertJ,Hamcrest,Truth等第三方断言库。

JUnit Jupiter的org.junit.jupiter.Assertions类没有提供类似于JUnit 4的org.junit.Assert类的assertThat()方法。

开发人员可以自由使用他们选择的断言库。例如,匹配器和fluent API的组合可以用来使断言更具描述性和可读性。

Hamcrest

依赖信息

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest</artifactId>
    <version>2.2</version>
    <scope>test</scope>
</dependency>

只要Hamcrest库已经添加到classpath中,就可以静态地导入诸如assertThat(),is()和equalTo()之类的方法

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.jupiter.api.Test;


public class HamcrestAssertTests {

    @Test
    void hamcrestAssertTest(){
        // Hamcrest断言
        assertThat(1+1, is(equalTo(2)));
    }
}

Mathers 匹配器

  • is():是
  • not():不是
  • equalTo():相等
  • hasItem():包含
  • hasItems():包含多个
  • allOf():全部为真则为真
  • anyOf():任一为真则为真
  • both().and():且
  • either().or():或
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

public class TestHamcrest {

    @Test
    void testIs(){
        assertThat("Hogwarts", is("Hogwarts"));

    }

    @Test
    void testNot(){
        assertThat("Hello", not("Hogwarts"));
        assertThat("Hello", is(not(equalTo("Hogwarts"))));
        assertThat("Hello", is(not(instanceOf(Integer.class))));
    }

    @Test
    void testEqualTo(){
        assertThat("Hogwarts", equalTo("Hogwarts"));
        assertThat("Hogwarts", is(equalTo("Hogwarts")));
    }

    @Test
    void testHasItem(){
        List<String> lan = Arrays.asList("Java", "JavaScript");

        assertThat(lan, hasItem("Java"));
        assertThat(lan, hasItem(isA(String.class)));
    }

    @Test
    void testHasItems(){
        List<String> lan = Arrays.asList("Java", "JavaScript");

        assertThat(lan, hasItems("Java", "JavaScript"));
        assertThat(lan, hasItems(isA(String.class), startsWith("J")));
    }

    @Test
    void testAllOf(){
        assertThat("Hogwarts", allOf(
                isA(String.class),
                startsWith("H"),
                containsString("art")
        ));
    }

    @Test
    void testAnyOf(){
        assertThat("Hogwarts", anyOf(
                isA(String.class),  // true
                startsWith("J")     // false
        ));
    }

    @Test
    void testBothAnd(){
        assertThat("Hogwarts",
                both(startsWith("H")).and(isA(String.class)));
    }

    @Test
    void testEitherOr(){
        assertThat("Hogwarts",
                either(startsWith("H")).or(isA(Integer.class)));
    }
}