spring boot 单元测试JUnit5使用断言Assertions和假定Assumptions、嵌套、参数测试
本文基于spirng boot 2.7.11, 大家注意自己的版本
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库
SpringBoot 2.4 以上版本移除了默认对 Vintage 的依赖
源码地址:https://gitcode.net/qq_39339588/springboot.git
文章目录
1. 标记单元测试类和方法
@SpringBootTest注解,可以标记为测试类
@Test注解标记是测试方法
@DisplayName注解是标记个名称
@SpringBootTestpublicclassHelloWorldTest{/**
* 断言基础
*/@Test@DisplayName("简单断言")publicvoidsimple(){}}
2. 断言的简单使用
1)基本类型和对象的断言
/**
* 基本类型和对象的断言
*/@Test@DisplayName("简单断言")publicvoidsimple(){Assertions.assertEquals(3,1+2,"不相等");Assertions.assertNotEquals(3,1+1,"相等了");//断言对象Assertions.assertNotSame(newObject(),newObject(),"对象相同");Object o =newObject();Assertions.assertSame(o, o,"断言不相等了");Assertions.assertFalse(1>2);Assertions.assertTrue(1<2);Assertions.assertNull(null);Assertions.assertNotNull(newObject());}
2)数组断言
@DisplayName("数组断言")@Testpublicvoidarray(){// 断言两个数组对象不相等Assertions.assertNotEquals(newint[]{1,2},newint[]{1,2});}
3)组合断言
@DisplayName("组合断言")@Testpublicvoidall(){// 断言所多个断言方法都正确Assertions.assertAll("组合断言",()->Assertions.assertEquals(2,1+1),()->Assertions.assertTrue(1>0));}
4)异常断言
@DisplayName("异常断言")@Testpublicvoidexception(){// 断言方法 会出现异常ArithmeticException arithmeticException =Assertions.assertThrows(ArithmeticException.class,()->System.out.println(1%0));
arithmeticException.printStackTrace();}
5)超时断言
@DisplayName("超时断言")@TestpublicvoidtimeOut(){// 断言方法执行不会超过1秒Assertions.assertTimeout(Duration.ofMillis(1000),()->Thread.sleep(500));}
6)快速失败断言
@DisplayName("快速失败")@TestpublicvoidfailFast(){// 触发快速失败后AssertionFailedError ex =Assertions.assertThrows(AssertionFailedError.class,()->{Assertions.fail("触发快速失败");});
ex.printStackTrace();}
3. 前置条件断言,假设假定
执行断言的前提条件,如果假定成功true,才会去执行
/**
* 前置条件,假设假定
*/@DisplayName("前置条件")@Testpublicvoidassuming(){String evn ="dev";// 执行断言的前提条件,如果假定成功true,才会去执行下一行,如果假定失败,下边的就不执行了Assumptions.assumeTrue(Objects.equals(evn,"dev"));Assumptions.assumeFalse(Objects.equals(evn,"prod"));System.out.println("dev和不是prod,执行了");Assumptions.assumeTrue(Objects.equals(evn,"dev1"));System.out.println("dev1,这句会忽略,不会执行输出");}/**
* 假定成功true,才会去执行 执行器方法
*/@DisplayName("前置条件That")@TestpublicvoidassumingThat(){// 假定成功,才会去执行 执行器方法Assumptions.assumingThat(Objects.equals("dev","dev"),()->{System.out.println("in dev");});}
4. 嵌套@Nested
内部嵌套,每次会先走外层的beforeEach,在走内部的beforeEach;支持嵌套的嵌套
@DisplayName("单元测试示例")@SpringBootTestpublicclassHelloWorldTest{Stack<Object> stack;/**
* 内部嵌套,每次会先走外层的beforeEach,在走内部的beforeEach
*/@DisplayName("内部嵌套测试")@NestedclassInnerTest{@BeforeEachvoidnewStack(){// 创建一个栈对象
stack =newStack<>();}@DisplayName("检查是否为空")@TestvoidisEmpty(){Assertions.assertTrue(stack.isEmpty());}@DisplayName("抛出一个栈pop异常")@TestvoidthrowExceptionWhenPop(){Assertions.assertThrows(EmptyStackException.class, stack::pop);}@DisplayName("抛出一个栈peek异常")@TestvoidthrowExceptionWhenPeek(){Assertions.assertThrows(EmptyStackException.class, stack::peek);}@Nested@DisplayName("内部的内部嵌套测试")classInnerInnerTest{String item ="item";@BeforeEachvoidpushAnItem(){// 放入一个元素
stack.push(item);}@DisplayName("不为空了")@TestvoidisNotEmpty(){Assertions.assertFalse(stack.isEmpty());}@DisplayName("取出一个来,用pop")@TestvoidreturnItemByPop(){Assertions.assertEquals(item, stack.pop());Assertions.assertTrue(stack.isEmpty());}@DisplayName("取出一个来,用peek")@TestvoidreturnItemByPeek(){Assertions.assertEquals(item, stack.peek());Assertions.assertFalse(stack.isEmpty());}}}
5. 参数化测试
参数化测试,让单元测试的方法支持接收传入的参数
将可以使用不同的参数进行多次单元测试,有多少套参数,就执行多少次单元测试
而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码
1)@ValueSource注解,基本类型入参
/**
* @ValueSource:为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
* @param params
*/@DisplayName("参数化测试,值来源")@ParameterizedTest@ValueSource(strings ={"a","b","c"})publicvoidparameterizedTest(String params){// 会执行3次,分别执行a,b,cSystem.out.println(params);Assertions.assertTrue(StringUtils.isNotBlank(params));}
2)@NullSource注解,null入参
/**
* null入参
*
* @param params
*/@DisplayName("null的入参")@ParameterizedTest@NullSourcepublicvoidtestNull(String params){Assertions.assertNull(params);}
3)@EnumSource注解,枚举入参
/**
* 枚举入参,会把枚举遍历一遍,分别执行一次方法
*/@DisplayName("枚举的入参")@ParameterizedTest@EnumSource(TestEnum.class)publicvoidtestEnumSource(TestEnum params){System.out.println("state:"+ params.state +",msg:"+ params.msg);// state:1,msg:好// state:2,msg:不好Assertions.assertNotNull(params);}/**
* 枚举类
*/@Getter@AllArgsConstructorpublicenumTestEnum{GOOD(1,"好"),BAD(2,"不好");int state;String msg;}
4)@CsvSource注解,多参数入参
@DisplayName("参数化测试,@CsvSource")@ParameterizedTest@CsvSource({"a,b,c"})voidparameterizedTestCsvSource(String a,String b,String c){// 默认使用逗号分隔System.out.println(a + b + c);Assertions.assertNotNull(a);}@DisplayName("参数化测试,@CsvSource2")@ParameterizedTest@CsvSource(value ={"a,b,c-D"}, delimiterString ="-")voidparameterizedTestCsvSource2(String abc,String d){// 默认使用逗号分隔,指定分隔符"-"System.out.println(abc);System.out.println(d);Assertions.assertNotNull(abc);// a,b,c// D}
5)@CsvFileSource,参数文件入参
可以把文件中的内容当做参数,批量来执行,下边附带了my.csv和my2.csv文件内容
注意,要在测试目录下,新建resources目录,再放入my.csv和my2.csv文件
/**
* 参数文件
*
* @param methodName
*/@DisplayName("参数化测试,@CsvFileSource")@ParameterizedTest@CsvFileSource(resources ="/my.csv")voidparameterizedTestWithCsvFileSource(String methodName){// 测试目录下,新建resources目录System.out.println(methodName);Assertions.assertNotNull(methodName);}@DisplayName("参数化测试,@CsvFileSource")@ParameterizedTest@CsvFileSource(resources ="/my2.csv", delimiterString ="|")voidparameterizedTestWithCsvFileSource2(String name,Integer age){// 测试目录下,新建resources目录System.out.println(name +":"+ age);Assertions.assertNotNull(name);// a:18// b:17// c:20}
my.csv文件
1
2
3
4
my2.csv
a|18
b|17
c|20
6)@MethodSource注解,方法返回值入参
把一个方法的返回值,作为测试用例方法的参数
/**
* 动态参数
*/@DisplayName("参数化测试,方法来源")@ParameterizedTest@MethodSource("method1")// 如果不指定方法名称,会去找与自己相同名称的静态方法publicvoidparameterizedTestWithMethodParam(String params){// MethodSource("method1") 接收这个方法的返回值,之后会执行2次,a,bSystem.out.println(params);Assertions.assertNotNull(params);}staticStream<String>method1(){returnStream.of("a","b");}@DisplayName("参数化测试,方法来源,多参数")@ParameterizedTest@MethodSource// 如果不指定方法名称,会去找相同名称的静态方法publicvoidparameterizedTestWithMethodMultipleParams(String name,Integer age){System.out.println(name +":"+ age);// a:18// b:17// c:20Assertions.assertNotNull(name);}staticStream<Arguments>parameterizedTestWithMethodMultipleParams(){returnStream.of(Arguments.arguments("a",18),Arguments.arguments("b",17),Arguments.arguments("c",20));}
7) @ArgumentsSource注解,自定义参数入参
/**
* 实现ArgumentsProvider接口,并在测试方法上使用@ArgumentsSource注解。
*/@DisplayName("@ArgumentsSource注解")@ParameterizedTest@ArgumentsSource(MyArgumentsProvider.class)publicvoidtestArgumentsSource(String name,int age){System.out.println(name +":"+ age);// aa:18// bb:20// cc:30Assertions.assertNotNull(name);}
版权归原作者 Goldchenn 所有, 如有侵权,请联系我们删除。