单元测试在系统重构时能发挥巨大的做用,能够在重构后快速测试新的接口是否与重构前有出入
依赖
<!-- SpringBoot 2.4 以上版本移除了默认对 Vintage 的依赖。如果需要兼容junit4需要自行引入(不能使用junit4的功能 @Test)--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 兼容junit4需要自行引入vintage --> <dependency> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> </exclusion> </exclusions> </dependency> <!--SpringBoot2.3.1--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency>
@SpringBootTest class WebAdminApplicationTests { @Test void contextLoads() { } }
- junit5
import org.junit.jupiter.api.*; import java.util.concurrent.TimeUnit; @DisplayName("Junit5Test测试类") public class Junit5Test { @DisplayName("测试displayname注解") @Test void testDisplayName(){ System.out.println(1); } @BeforeEach void testBeforeEach() { System.out.println("测试就要开始了"); } @AfterEach void testAfterEach() { System.out.println("测试就要结束了"); } @Timeout(value=500, unit = TimeUnit.MILLISECONDS) @Test void testTimeout() throws InterruptedException { Thread.sleep(600); } @RepeatedTest(5) // 重复执行5次 @Test void testRepeatedTest() { System.out.println("1"); } }
注解
@BeforeEach:在每一个单元测试方法执行前都执行一遍
@BeforeAll:在每一个单元测试方法执行前执行一遍(只执行一次)
@DisplayName(“商品入库测试”):用于指定单元测试的名称
@Disabled:当前单元测试置为无效,即单元测试时跳过该测试
@RepeatedTest(n):重复性测试,即执行n次
@ParameterizedTest:参数化测试
@ValueSource(ints = {1, 2, 3}):参数化测试提供数据
断言
- JUnit Jupiter提供了强大的断言方法用以验证结果,在使用时须要借助java8的新特性lambda表达式,均是来自org.junit.jupiter.api.Assertions包的static方法。code
assertTrue与assertFalse用来判断条件是否为true或false
- assertTrue与assertFalse用来判断条件是否为true或false
@Test @DisplayName("测试断言equals") void testEquals() { assertTrue(3 < 4); }
assertNull与assertNotNull用来判断条件是否为 null
@Test @DisplayName("测试断言NotNull") void testNotNull() { assertNotNull(new Object()); }
assertThrows用来判断执行抛出的异常是否符合预期,并可使用异常类型接收返回值进行其余操做
@Test @DisplayName("测试断言抛异常") void testThrows() { ArithmeticException arithExcep = assertThrows(ArithmeticException.class, () -> { int m = 5/0; }); assertEquals("/ by zero", arithExcep.getMessage()); }
assertTimeout用来判断执行过程是否超时
@Test @DisplayName("测试断言超时") void testTimeOut() { String actualResult = assertTimeout(ofSeconds(2), () -> { Thread.sleep(1000); return "a result"; }); System.out.println(actualResult); }
assertAll是组合断言,当它内部全部断言正确执行完才算经过
@Test @DisplayName("测试组合断言") void testAll() { assertAll("测试item商品下单", () -> { //模拟用户余额扣减 assertTrue(1 < 2, "余额不足"); }, () -> { //模拟item数据库扣减库存 assertTrue(3 < 4); }, () -> { //模拟交易流水落库 assertNotNull(new Object()); } ); }
- 重复性测试
在许多场景中咱们须要对同一个接口方法进行重复测试,例如对幂等性接口的测试。
JUnit Jupiter经过使用@RepeatedTest(n)指定须要重复的次数
@RepeatedTest(3) @DisplayName("重复测试") void repeatedTest() { System.out.println("调用"); }
参数化测试
参数化测试能够按照多个参数分别运行屡次单元测试这里有点相似于重复性测试,只不过每次运行传入的参数不用。须要使用到@ParameterizedTest,同时也须要@ValueSource提供一组数据,它支持八种基本类型以及String和自定义对象类型,使用极其方便。
@ParameterizedTest @ValueSource(ints = {1, 2, 3}) @DisplayName("参数化测试") void paramTest(int a) { assertTrue(a > 0 && a < 4); }
- 内嵌测试
JUnit5提供了嵌套单元测试的功能,能够更好展现测试类之间的业务逻辑关系,咱们一般是一个业务对应一个测试类,有业务关系的类其实能够写在一块儿。这样有利于进行测试。并且内联的写法能够大大减小没必要要的类,精简项目,防止类爆炸等一系列问题。
@SpringBootTest @AutoConfigureMockMvc @DisplayName("Junit5单元测试") public class MockTest { //.... @Nested @DisplayName("内嵌订单测试") class OrderTestClas { @Test @DisplayName("取消订单") void cancelOrder() { int status = -1; System.out.println("取消订单成功,订单状态为:"+status); } } }