JUnit5简介
JUnit5官网
JUnit5= JUnit Platform + JUnit Jupiter + JUnit Vintag
JUnit Platform:
用于JVM上启动测试框架的基础服务,提供命令行,IDE和构建工具等方式执行测试的支持;
JUnit Jupiter:
包含JUnit新的编程模型和扩展模型,主要就是用于编写测试代码和扩展代码;
JUnit Vintage:
用于在JUnit5中兼容运行JUnit3.x和JUnit4.x的测试用例。
JUnit5架构
JUnit5特征
JUnit 5主要特性:
•提供全新的断言和测试注解,支持测试类内嵌;
•更丰富的测试方式:支持动态测试,重复测试,参数化测试等;
•实现了模块化,让测试执行和测试发现等不同模块解耦,减少依赖;
•提供对 Java 8 +版本的支持,如 Lambda 表达式,Stream API等。
JUnit5用法
JUnit5与JUnit4annotation的差异
JUnit4 | Junit5 | 说明 |
---|---|---|
@Test | @Test | 标记方法为测试方法 |
@Before | @BeforeEach | 在每个测试执行之前执行 |
@After | @AfterEach | 在每个测试执行之后执行 |
@BeforeClass | @BeforeAll | 只执行一次,在所有测试和 @BeforeEach 注解方法之前 |
@AfterClass | @AfterAll | 只执行一次,在所有测试和 @AfterEach注解方法之后 |
@Ignore | @Disabled | 禁用执行测试 |
JUnit5特有annotation
Junit5 | 说明 |
---|---|
@DisplayName | 用来定义一个测试类并指定用例在测试报告中的展示名称 |
@Nested | 内嵌测试类 |
@RepeatedTest | 重复性测试 |
实例1
通过Maven导入JUnit5的jar包
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
第一个测试代码
import org.junit.jupiter.api.*;
@DisplayName("我的第一个Junit5测试用例")
public class MyFirstJunit5Test {
@BeforeAll
public static void init() {
System.out.println("初始化数据");
}
@AfterAll
public static void cleanUp() {
System.out.println("清理数据");
}
@BeforeEach
public void tearup() {
System.out.println("当前测试方法开始");
}
@AfterEach
public void tearDown() {
System.out.println("当前测试方法结束");
}
@DisplayName("我的第一个测试")
@Test
void testFirstTest(){
System.out.println("我的第一个测试开始");
}
@DisplayName("我的第二个测试")
@Test
void testSecondTest(){
System.out.println("我的第二个测试开始");
}
@DisplayName("我的第三个测试")
@Test
void testThirdTest(){
System.out.println("我的第三个测试开始");
}
}
实例2(内嵌测试方法)
@DisplayName("内嵌测试类")
public class NestUnitTest {
@BeforeEach//在每个测试执行之前执行
void init() {
System.out.println("测试方法执行前准备");
}
@Nested//定义内嵌测试类
@DisplayName("第一个内嵌测试类")//定义用例在测试报告中的展示名称
class FirstNestTest {
@Test//定义测试方法
void test1() {
System.out.println("第一个内嵌测试类执行测试1");
}
@Test//定义测试方法
void test2() {
System.out.println("第一个内嵌测试类执行测试2");
}
}
@Nested//定义内嵌测试类
@DisplayName("第二个内嵌测试类")//定义用例在测试报告中的展示名称
class SecondNestTest {
@Test//定义测试方法
void test1() {
System.out.println("第二个内嵌测试类执行测试1");
}
@Test//定义测试方法
void test2() {
System.out.println("第二个内嵌测试类执行测试2");
}
}
}
实例3(assertAll 方法进行断言)
public class AssertAllTest {
@Test
void testGroupAssertions() {
int[] numbers = {0, 1, 2, 3, 4};
Assertions.assertAll("numbers",//下面所有条件成立,才通过
() -> Assertions.assertEquals(numbers[1], 1),//断言相等
() -> Assertions.assertEquals(numbers[3], 3),//断言相等
() -> Assertions.assertEquals(numbers[4], 4) //断言相等
);
}
}
实例4(超时方法测试)
public class AssertTimeoutTest {
@Test
@DisplayName("超时方法测试")
void test_should_complete_in_one_second(){
//断言超时
Assertions.assertTimeoutPreemptively(Duration.of(1, ChronoUnit.SECONDS),
() -> Thread.sleep(1000));
}
}
实例5(异常测试)
public class AssertThrowsExceptionTest {
@Test
@DisplayName("测试捕获的异常")
void assertThrowsException() {
String str = null;
//1、断言抛出异常,2,抛出IllegalArgumentException异常
Assertions.assertThrows(IllegalArgumentException.class, () -> {
Integer.valueOf(str);
});
}
}
实例6(参数化测试)
注解 | 说明 |
---|---|
_ @valueSource _ | _ 通过注解可以直接指定携带的运行参数 _ |
_ @EnumSource _ | _ 枚举参数元,允许我们通过将参数值有给定的Enum枚举类型传入 _ |
_ @MethodSource _ | _ 通过其他的Java方法函数来作为参数源 _ |
_ @ArgumentSource _ | _ 参数类参数源,应用类必须实现ArgumentsProvide接口 _ |
_ @CSVSource _ | _ csv格式作为参数源 _ |
_ @CSVFileSource _ | _ csv文件作为参数源 _ |
public class ParameterizedUnitTest {
@ParameterizedTest
@ValueSource(ints = {2,4,8})
void testNumberShouldBeEven(int num){
Assertions.assertEquals(0,num % 2);
}
@ParameterizedTest
@ValueSource(strings = {"Effective Java","Code Complete","Clean Code"})
void testPrintTitle(String title){
System.out.println(title);
}
@ParameterizedTest
@CsvSource({"1,One", "2,Two", "3,Three"})
void testDataFromCsv(long id, String name) {
System.out.printf("id: %d, name: %s", id, name);
}
@ParameterizedTest
@CsvSource(value = {"1|2","3|4"},delimiter = '|')
public void parameterizedCvsSourceTest(String fruit, int rank) {
System.out.println(fruit);
System.out.println(rank);
}
@ParameterizedTest
@CsvFileSource(resources = {"/resources/CsvSource(1).csv"})
public void parameterizedCsvFileSourceTest(String id,String name){
System.out.println(id);
System.out.println(name);
}
@ParameterizedTest
@EnumSource(value = TimeUnit.class,mode = EnumSource.Mode.INCLUDE,names = {"DAYS","SECONDS"})
public void parameterizedEnumSourceTest(TimeUnit timeUnit){
System.out.println(timeUnit);
}
@ParameterizedTest
@EnumSource(value = TimeUnit.class,mode = EnumSource.Mode.MATCH_ANY,
names = {"^(M|N).+SECONDS$","SECONDS"})
public void parameterizedEnumSourceTest1(TimeUnit timeUnit){
System.out.println(timeUnit);
}
// @ParameterizedTest
// @MethodSource("methodSourceTestFactory")
// public void parameterizedMethodSourceTest(Student student){
// System.out.println(student.getName());
// }
//
// public static Stream<Student> methodSourceTestFactory(){
// Student student = new Student("Junit5",23);
// Stream<Student> student1 = Stream.of(student);
// return student1;
// }
@ParameterizedTest
@NullAndEmptySource //(等同于@NullSource和@EmptySource 两个)
public void parameterizedNullAndEmptySourceTest(String nullSource){
System.out.println(nullSource.length());
}
}
使用JUnit 5优点
- JUnit 5利用了Java 8或更高版本的特性,例如lambda函数,使测试更强大,更容易维护;
- JUnit 5为描述、组织和执行测试添加了一些非常有用的新功能。例如,测试得到了更好的显示名称,并且可以分层组织;
- JUnit 5被组织成多个库,所以只将你需要的功能导入到你的项目中。通过Maven和Gradle等构建系统,包含合适的库很容易;
- JUnit 5可以同时使用多个扩展,这是JUnit 4无法做到的(一次只能使用一个runner)。这意味着你可以轻松地将Spring扩展与其他扩展(如你自己的自定义扩展)结合起来。