在SpringBoot2中,它自带了单元测试的依赖,使用的单元测试不再是Junit4,而是Junit5,并且在SpringBoot2.4之后,SpringBoot不在支持Junit4,如果想使用Junit4需要另外导入依赖
Junit5常用注解
- **@Test 😗*表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试
- **@ParameterizedTest 😗*表示方法是参数化测试,下方会有详细介绍
- **@RepeatedTest 😗*表示方法可重复执行,下方会有详细介绍
- **@DisplayName 😗*为测试类或者测试方法设置展示名称
- **@BeforeEach 😗*表示在每个单元测试之前执行
- **@AfterEach 😗*表示在每个单元测试之后执行
- **@BeforeAll 😗*表示在所有单元测试之前执行
- **@AfterAll 😗*表示在所有单元测试之后执行
- **@Tag 😗*表示单元测试类别,类似于JUnit4中的@Categories
- **@Disabled 😗*表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
- **@Timeout 😗*表示测试方法运行如果超过了指定时间将会返回错误
- **@ExtendWith 😗*为测试类或测试方法提供扩展类引用
想要使用Junit5,必须要在测试类前标注SpringBootTest注解
@DisplayName("测试常用注解")
@SpringBootTest
public class Junit5Test {
@Test
@DisplayName("展示名称")
void displayName(){
System.out.println("111");
}
@Test
@Disabled
@DisplayName("方法2")
void test2(){
System.out.println("222");
}
@Test
@DisplayName("超时报错")
@Timeout(value = 1,unit = TimeUnit.SECONDS)
void test3() throws InterruptedException {
Thread.sleep(2000);
}
@BeforeEach
void beforeEach(){
System.out.println("在测试方法前执行");
}
@AfterEach
void afterEach(){
System.out.println("在测试方法后执行");
}
@BeforeAll
static void beforeAll(){
System.out.println("在所有测试方法前执行");
}
@AfterAll
static void afterAll(){
System.out.println("在所有测试方法后执行");
}
}
断言(assertions)
小黄的个人理解,断言类似与判断,如果判断成立,则无事发生,否则报错
assertions类中的方法大多是静态方法,可以直接调用
@SpringBootTest
@DisplayName("断言测试")
public class AssertionsTest {
@Test
@DisplayName("测试assertEquals")
void test1(){
int a = 3 + 2;
assertEquals(6, a, "数学运算错误");
}
@Test
@DisplayName("测试assertSame")
void test2(){
Object obj1 = new Object();
Object obj2 = new Object();
assertSame(obj1,obj2,"两个对象不同");
}
@Test
@DisplayName("数组断言")
void test3(){
assertArrayEquals(new int[]{1,2},new int[]{2,1},"两个数组不同");
}
@Test
@DisplayName("组合断言")
void test4(){
assertAll("数学运算",()->{
assertEquals(6, 3+3, "数学运算错误");
},()->{
assertNotEquals(6, 3+3, "数学运算正确");
});
}
@Test
@DisplayName("超时断言")
void test5(){
//设置超过1秒报错
assertTimeout(Duration.ofMillis(1000),()->{
Thread.sleep(500);
});
}
@Test
@DisplayName("快速失败")
void test6(){
if(1==1){
fail("快速失败");
}
}
}
前置条件(assumptions)
前置条件有点像if判断,如果条件成立,接下去执行测试代码,如果不成立则不执行往后代码
@SpringBootTest
@DisplayName("前置条件")
public class AssumptionsTest {
@Test
@DisplayName("")
void test1(){
//如果条件成立,执行输出语句
Assumptions.assumeTrue(1==1);
System.out.println("111");
//如果条件返回值不为false则终止后面的代码
Assumptions.assumeFalse(1==1);
System.out.println("222");
}
}
嵌套测试
JUnit 5 可以通过 Java 中的内部类和@Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach 和@AfterEach 注解,而且嵌套的层次没有限制。
@DisplayName("A stack")
class TestingAStackDemo {
Stack<Object> stack;
@Test
@DisplayName("is instantiated with new Stack()")
void isInstantiatedWithNew() {
new Stack<>();
}
@Nested
@DisplayName("when new")
class WhenNew {
@BeforeEach
void createNewStack() {
stack = new Stack<>();
}
@Test
@DisplayName("is empty")
void isEmpty() {
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("throws EmptyStackException when popped")
void throwsExceptionWhenPopped() {
assertThrows(EmptyStackException.class, stack::pop);
}
@Test
@DisplayName("throws EmptyStackException when peeked")
void throwsExceptionWhenPeeked() {
assertThrows(EmptyStackException.class, stack::peek);
}
@Nested
@DisplayName("after pushing an element")
class AfterPushing {
String anElement = "an element";
@BeforeEach
void pushAnElement() {
stack.push(anElement);
}
@Test
@DisplayName("it is no longer empty")
void isNotEmpty() {
assertFalse(stack.isEmpty());
}
@Test
@DisplayName("returns the element when popped and is empty")
void returnElementWhenPopped() {
assertEquals(anElement, stack.pop());
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("returns the element when peeked but remains not empty")
void returnElementWhenPeeked() {
assertEquals(anElement, stack.peek());
assertFalse(stack.isEmpty());
}
}
}
}
参数化测试
参数化测试是JUnit5很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多便利。
利用**@ValueSource**等注解,指定入参,我们将可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码。
@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
@NullSource: 表示为参数化测试提供一个null的入参
@EnumSource: 表示为参数化测试提供一个枚举入参
@CsvFileSource:表示读取指定CSV文件内容作为参数化测试入参
@MethodSource:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
@ParameterizedTest
@DisplayName("参数化测试")
@ValueSource(ints = {1,2,3,4,5})
void test2(int i){
//i代表遍历ints中的数字
System.out.println(i);
}
@ParameterizedTest
@DisplayName("参数化测试——方法")
@MethodSource("method")
void test3(String str){
System.out.println(str);
}
static Stream<String> method() {
return Stream.of("apple", "banana");
}