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)));
}
}