当我把我的商城项目升级到SpringBoot2.7后,之前的很多测试方法都不能用了。原来SpringBootTest已经升级到支持JUnit5了,今天我们就来说说新版SpringBootTest的使用。有了它,我们再也不用用main方法来测试了!SpringBoot实战电商项目商城(50k+star)地址:https://github.com/macrozheng/mallJUnit简介JUnit是Java语言的单元测试框架,目前大多数Java开发环境都支持。JUnit测试也就是所谓的白盒测试,是在程序员了解程序内部逻辑的基础上进行的。使用JUnit可以让我们快速完成单元测试。SpringBootTest结合了JUnit和其他测试框架,提供方便、高效的测试方法。目前,SpringBoot2.7使用JUnit5。常用注解在使用SpringBootTest之前,我们先来了解一下它的常用注解,这些注解对使用起来很有帮助。详情请参考下表!注解函数@SpringBootTest用于指定启用SpringBootTest的测试类,默认会提供Mock环境。@ExtendWith如果只想开启Spring环境进行简单测试,不想开启SpringBoot环境,可以配置extension为:SpringExtension@Test指定方法为测试方法@TestMethodOrder用于配置测试类中方法的执行顺序策略。当配置为OrderAnnotation时,@Order用于配置方法的执行顺序。数字越小,执行顺序越高。@DisplayName用于指定测试类和测试方法的别名@BeforeAll在测试类的所有测试方法之前执行一次,可用于全局初始化@AfterAll在测试类的所有测试方法之后执行一次,可以使用用于全局销毁资源@BeforeEach在测试类的每个测试方法之前执行一次@AfterEach在测试类的每个测试方法之后执行一次。@Disabled禁用测试方法@RepeatedTest指定测试方法重复@ParameterizedTest指定参数化测试方法,类似重复执行,从@ValueSource获取参数@ValueSource用于参数化测试指定参数@AutoConfigureMockMvc开启自动配置MockMvc,可用于测试接口的基本使用。下面说说这些注解的基本使用,通过注解可以实现一些基本的单元测试。集成SpringBootTest如果想在项目中集成SpringBootTest,需要先在pom.xml中添加如下依赖。org.springframework.bootspring-boot-starter-testtest最简单的测试让我们从最简单的开始单元测试,使用@SpringBootTest注解开启单元测试,使用@Test指定测试方法,使用Assertions类的方法断言结果是否符合预期。具体代码如下。/***JUnit基础测试*宏创建于2022/10/11。*/@SpringBootTest公共类FirstTest{@Testpublicvoidtest(){inta=1;断言.assertEquals(1,a);}}然后点击测试方法左侧的按钮进行测试。执行完成后,我们可以在IDEA的执行窗口看到方法test已经通过。由于使用@SpringBootTest启用了SpringBoot环境,因此日志中会输出SpringBootbanner。指定测试方法顺序我们可以通过@TestMethodOrder注解和@Order注解来指定所有测试方法的执行顺序。具体代码如下。/***JUnit指定方法测试顺序*由宏创建于2022/10/10。*/@ExtendWith(SpringExtension.class)@TestMethodOrder(MethodOrderer.OrderAnnotation.class)publicclassMethodOrderTest{privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(MethodOrderTest.class);@Test@Order(1)@DisplayName("Amethodwhichorderis1")voidlowOrder(){LOGGER.info("lowOrdermethod");}@Test@Order(10)@DisplayName("阶数为10的方法")voidhighOrder(){LOGGER.info("highOrder方法");}}点击类左侧的测试按钮,可以直接运行类中的所有测试方法。这里因为我们使用@DisplayName注解给测试方法起别名,并且使用@ExtendWith指定运行环境为Spring而不是SpringBoot,所以日志中不会出现SpringBootbanner,执行速度会更快。对于生命周期测试,我们也可以通过JUnit5的生命周期注解来执行测试方法,比如在@BeforeAll注解指定的方法中进行全局初始化,在@AfterAll注解指定的方法中进行资源销毁。具体代码如下。/***JUnit生命周期测试*由宏创建于2022/10/10。*/@ExtendWith(SpringExtension.class)publicclassLifecycleTest{privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(LifecycleTest.class);@BeforeAllstaticvoidallInit(){LOGGER.info("allInit():在所有方法之前执行,只执行一次");}@BeforeEachvoideachInit(){LOGGER.info("eachInit():Executebeforethetestmethod,everyExecutebeforeeachtestmethod");}@TestvoidsuccessTest(){LOGGER.info("successTest():方法执行成功");}@AfterEachvoideachDown(){LOGGER.info("eachDown():AfterExecuteaftertestmethod,在每个测试方法之后执行");}@AfterAllstaticvoidallDown(){LOGGER.info("allDown():在测试方法之后执行,在每个测试方法之后执行");}}测试完成后,控制台输出日志如下。断言的使用我们可以通过Assertions类中提供的断言API对测试结果进行断言。比如我们可以使用fail方法直接断言方法执行失败并输出提示信息。/***JUnit断言测试*由宏创建于2022/10/11。*/@ExtendWith(SpringExtension.class)publicclassAssertTest{@TestvoidfailTest(){Assertions.fail("failTest():方法执行失败");}}测试方法执行后,会直接抛出异常信息。您还可以使用assertTrue、assertNull和assertEquals等方法来断言结果是否符合预期。/***JUnit断言测试*由宏创建于2022/10/11。*/@ExtendWith(SpringExtension.class)publicclassAssertTest{@TestvoidfailTest(){Assertions.fail("failTest():方法执行失败");}@TestvoidtrueTest(){Assertions.assertTrue(1==1);}@TestvoidtrueFalse(){Assertions.assertFalse(3<=2);}@TestvoidnullTest(){Stringstr=null;断言.assertNull(str);}@TestvoidnotNullTest(){Stringstr="test";断言.assertNotNull(str);}@TestvoidequalsTest(){Stringstr1="test";Stringstr2="测试";断言.assertEquals(str1,str2);}@TestvoidnotEqualsTest(){Stringstr1="test";字符串str2="测试";断言.assertNotEquals(str1,str2);您还可以使用assertThrows方法断言方法中抛出的异常。/***JUnit断言测试*由宏创建于2022/10/11。*/@ExtendWith(SpringExtension.class)publicclassAssertTest{privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(LifecycleTest.class);@TestvoidthrowsTest(){Assertions.assertThrows(NullPointerException.class,()->{Stringstr=null;LOGGER.info(str.toLowerCase());});}}也可以通过assertTimeout方法断言方法的执行时间。/***JUnit断言测试*由宏创建于2022/10/11。*/@ExtendWith(SpringExtension.class)publicclassAssertTest{@TestvoidtimeoutTest(){Assertions.assertTimeout(Duration.ofMillis(1000),()->{longsleepTime=2000;ThreadUtil.sleep(sleepTime);记录器。info("timeoutTest():休眠{}毫秒",sleepTime);});}}或者通过assertAll方法组合多个断言,Assertions类中提供了很多工具和方法,具体可以参考其代码。/***JUnit断言测试*由宏创建于2022/10/11。*/@ExtendWith(SpringExtension.class)publicclassAssertTest{@TestvoidassertAllTest(){Assertions.assertAll(()->{trueTest();},()->{nullTest();},()->{equalsTest();});}}其他测试SpringBootTest除了上面的测试功能,@Disabled还可以用来禁用一个测试方法。/***JUnit其他测试*由宏创建于2022/10/10。*/@ExtendWith(SpringExtension.class)publicclassOtherTest{@Test@Disabled("用于测试@Disabled注解")voiddisabledTest(){LOGGER.info("disabledTest():方法已执行");}}@RepeatedTest也可以用来实现循环测试。/***JUnit其他测试*由宏创建于2022/10/10。*/@ExtendWith(SpringExtension.class)publicclassOtherTest{privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(LifecycleTest.class);私有静态整数计数=0;@RepeatedTest(3)voidrepeatedTest(){count++;LOGGER.info("repeatedTest():重复执行第{}次",count);您还可以使用@ParameterizedTest来执行参数化测试。/***JUnit其他测试*由宏创建于2022/10/10。*/@ExtendWith(SpringExtension.class)publicclassOtherTest{privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(LifecycleTest.class);@ParameterizedTest@ValueSource(ints={1,2,3})publicvoidparameterizedTest(inta){LOGGER.info("parameterizedTest():a={}",a);}}运行以上测试方法后,具体测试结果如下。项目实战上面介绍了SpringBootTest的基本使用,下面我们结合项目来使用。Dao层测试如果我们的项目需要测试数据访问层Dao中的方法,可以直接注入Mapper接口,在测试方法中直接调用。这里我们测试Mapper根据ID查询品牌的方法。/***Dao层方法测试*宏创建于2022/10/11。*/@SpringBootTestpublicclassMapperTest{privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(MapperTest.class);@Autowired私有PmsBrandMapperbrandMapper;@TestvoidtestGetById(){longid=6;PmsBrandpmsBrand=brandMapper.selectByPrimaryKey(id);LOGGER.info("品牌名称:{}",pmsBrand.getName());Assertions.assertEquals("小米",pmsBrand.getName());}}Service层测试同业务层Service中的方法测试一样,直接注入Service接口,在测试方法中直接调用即可。这里测试根据ID查询品牌的Service方法。/***服务层方法测试*宏创建于2022/10/11。*/@SpringBootTestpublicclassServiceTest{privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(ServiceTest.class);@Autowired私有PmsBrandService品牌服务;@TestvoidtestGetById(){longid=6;PmsBrandpmsBrand=brandService.getBrand(id);LOGGER.info("品牌名称:{}",pmsBrand.getName());Assertions.assertEquals("小米",pmsBrand.getName());}}Controller层测试为了测试Controller层的方法,有时候我们需要模拟请求,就用MockMvc,这里是模拟测试下分页查询品牌列表的接口。/***Controller层方法测试*宏创建于2022/10/11。*/@SpringBootTest@AutoConfigureMockMvcpublicclassControllerTest{@AutowiredprivateMockMvcmockMvc;@TestvoidmvcTest()throwsException{//模拟发送请求访问接口mockMvc.perform(MockMvcRequestBuilders.get("/brand/list")//设置请求地址.param("pageNum","1")//setrequestparameter.param("pageSize","5")).andExpect(MockMvcResultMatchers.status().isOk())//断言返回状态码为200.andDo(MockMvcResultHandlers.print())//在控制台打印log.andReturn();//返回请求结果}}由于我们选择了在控制台输出日志,所以控制台会输出如下信息。总结今天带大家体验一下SpringBootTest。作为SpringBoot官方的测试框架,确实很强大。由于主要基于JUnit5,其用法与JUnit5基本相同,用于单元测试,无需启动整个项目,更快更好!参考JUnit5官方文档:https://junit.org/junit5/docs...项目源码地址https://github.com/macrozheng...