之前把我的mall我的项目降级到Spring Boot 2.7的时候,很多之前的测试方法都不能用了,原来是Spring Boot Test曾经降级反对JUnit 5了。明天咱们来聊聊新版Spring Boot Test的应用,有了它,咱们就不须要再应用main办法来测试了!

SpringBoot实战电商我的项目mall(50k+star)地址:https://github.com/macrozheng/mall

JUnit 简介

JUnit是一款Java语言的单元测试框架,目前大多数Java开发环境都曾经反对它了。JUnit测试也就是所谓的白盒测试,在程序员晓得程序外部逻辑的根底上进行的测试,应用JUnit能让咱们疾速地实现单元测试。Spring Boot Test将JUnit和其余测试框架联合起来,提供了便捷高效的测试伎俩,目前Spring Boot 2.7版本采纳的是JUnit 5。

罕用注解

在应用Spring Boot Test之前,咱们先来理解下它罕用的注解,这对应用它很有帮忙,具体参考下表即可!
注解作用
@SpringBootTest用于指定测试类启用Spring Boot Test,默认会提供Mock环境
@ExtendWith如果只想启用Spring环境进行简略测试,不想启用Spring Boot环境,能够配置扩大为:SpringExtension
@Test指定办法为测试方法
@TestMethodOrder用于配置测试类中办法的执行程序策略,配置为OrderAnnotation时,按@Order程序执行
@Order用于配置办法的执行程序,数字越低执行程序越高
@DisplayName用于指定测试类和测试方法的别名
@BeforeAll在测试类的所有测试方法前执行一次,可用于全局初始化
@AfterAll在测试类的所有测试方法后执行一次,可用于全局销毁资源
@BeforeEach在测试类的每个测试方法前都执行一次
@AfterEach在测试类的每个测试方法后都执行一次
@Disabled禁用测试方法
@RepeatedTest指定测试方法反复执行
@ParameterizedTest指定参数化测试方法,相似反复执行,从@ValueSource中获取参数
@ValueSource用于参数化测试指定参数
@AutoConfigureMockMvc启用MockMvc的主动配置,可用于测试接口

根本应用

上面咱们来聊聊这些注解的根本应用,通过它们能够实现一些根本的单元测试。

集成Spring Boot Test

如果你想在我的项目中集成Spring Boot Test的话,须要先在pom.xml中增加如下依赖。

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-test</artifactId>    <scope>test</scope></dependency>

最简略的测试

  • 咱们先来一个最简略的单元测试,应用@SpringBootTest注解启用单元测试,应用@Test指定测试方法,应用Assertions类的办法来断言后果是否合乎预期,具体代码如下。
/** * JUnit根本测试 * Created by macro on 2022/10/11. */@SpringBootTestpublic class FirstTest {    @Test    public void test() {        int a=1;        Assertions.assertEquals(1,a);    }}
  • 而后点击测试方法左侧按钮即可进行测试。

  • 执行实现后咱们在IDEA的执行窗口中就能够看到办法测试通过了,因为应用@SpringBootTest启用了Spring Boot环境,日志中会输入Spring Boot的banner。

指定测试方法程序

  • 咱们能够通过@TestMethodOrder注解和@Order注解来指定所有测试方法的执行程序,具体代码如下。
/** * JUnit指定办法测试程序 * Created by macro on 2022/10/10. */@ExtendWith(SpringExtension.class)@TestMethodOrder(MethodOrderer.OrderAnnotation.class)public class MethodOrderTest {    private static final Logger LOGGER = LoggerFactory.getLogger(MethodOrderTest.class);    @Test    @Order(1)    @DisplayName("order为1的办法")    void lowOrder(){        LOGGER.info("lowOrder method");    }    @Test    @Order(10)    @DisplayName("order为10的办法")    void highOrder(){        LOGGER.info("highOrder method");    }}
  • 点击类左侧测试按钮,能够间接运行该类中的所有测试方法。

  • 这里因为咱们应用了@DisplayName注解给测试方法取了个别名,而且咱们应用了@ExtendWith指定了运行环境为Spring而不是Spring Boot,所以日志中不会呈现Spring Boot的banner,执行速度也更快。

生命周期测试

  • 咱们还能够通过JUnit 5的生命周期注解来执行测试方法,比方在@BeforeAll注解指定的办法中做全局初始化,在@AfterAll注解指定的办法中做资源的销毁,具体代码如下。
/** * JUnit生命周期测试 * Created by macro on 2022/10/10. */@ExtendWith(SpringExtension.class)public class LifecycleTest {    private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleTest.class);    @BeforeAll    static void allInit(){        LOGGER.info("allInit():在所有办法前执行,只执行一次");    }    @BeforeEach    void eachInit(){        LOGGER.info("eachInit():在测试方法前执行,每个测试方法前都执行");    }    @Test    void successTest() {        LOGGER.info("successTest():办法执行胜利");    }    @AfterEach    void eachDown(){        LOGGER.info("eachDown():在测试方法后执行,每个测试方法后都执行");    }    @AfterAll    static void allDown(){        LOGGER.info("allDown():在测试方法后执行,每个测试方法后都执行");    }}
  • 测试实现后,控制台输入日志如下。

断言的应用

咱们能够通过Assertions类中提供的断言API来断言测试后果。
  • 例如咱们能够应用fail办法间接断言办法执行失败并输入提示信息。
/** * JUnit断言测试 * Created by macro on 2022/10/11. */@ExtendWith(SpringExtension.class)public class AssertTest {    @Test    void failTest() {        Assertions.fail("failTest():办法执行失败");    }}
  • 测试方法执行后会间接抛出异样信息。

  • 还能够通过assertTrueassertNullassertEquals这类办法来断言后果是否合乎预期。
/** * JUnit断言测试 * Created by macro on 2022/10/11. */@ExtendWith(SpringExtension.class)public class AssertTest {    @Test    void failTest() {        Assertions.fail("failTest():办法执行失败");    }    @Test    void trueTest(){        Assertions.assertTrue(1==1);    }    @Test    void trueFalse(){        Assertions.assertFalse(3<=2);    }    @Test    void nullTest(){        String str = null;        Assertions.assertNull(str);    }    @Test    void notNullTest(){        String str = "test";        Assertions.assertNotNull(str);    }    @Test    void equalsTest(){        String str1 = "test";        String str2 = "test";        Assertions.assertEquals(str1,str2);    }    @Test    void notEqualsTest(){        String str1 = "test";        String str2 = "test";        Assertions.assertNotEquals(str1,str2);    }}
  • 也能够应用assertThrows办法来断言办法中抛出的异样。
/** * JUnit断言测试 * Created by macro on 2022/10/11. */@ExtendWith(SpringExtension.class)public class AssertTest {    private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleTest.class);    @Test    void throwsTest(){        Assertions.assertThrows(NullPointerException.class,()->{            String str = null;            LOGGER.info(str.toLowerCase());        });    }}
  • 还可通过assertTimeout办法断言办法的执行工夫。
/** * JUnit断言测试 * Created by macro on 2022/10/11. */@ExtendWith(SpringExtension.class)public class AssertTest {    @Test    void timeoutTest(){        Assertions.assertTimeout(Duration.ofMillis(1000),()->{            long sleepTime = 2000;            ThreadUtil.sleep(sleepTime);            LOGGER.info("timeoutTest():休眠{}毫秒",sleepTime);        });    }}
  • 或者通过assertAll办法将几个断言联合起来应用,Assertions类中提供的工具办法很多,具体能够参考它的代码。
/** * JUnit断言测试 * Created by macro on 2022/10/11. */@ExtendWith(SpringExtension.class)public class AssertTest {    @Test    void assertAllTest(){        Assertions.assertAll(()->{            trueTest();        },()->{            nullTest();        },()->{            equalsTest();        });    }}

其余测试

  • Spring Boot Test除了上述测试性能,还能够应用@Disabled来禁用某个测试方法。
/** * JUnit其余测试 * Created by macro on 2022/10/10. */@ExtendWith(SpringExtension.class)public class OtherTest {    @Test    @Disabled("用于测试@Disabled注解")    void disabledTest() {        LOGGER.info("disabledTest():办法被执行");    }}
  • 也能够应用@RepeatedTest来实现循环测试。
/** * JUnit其余测试 * Created by macro on 2022/10/10. */@ExtendWith(SpringExtension.class)public class OtherTest {    private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleTest.class);    private static int count = 0;    @RepeatedTest(3)    void repeatedTest() {        count++;        LOGGER.info("repeatedTest():反复执行第{}次",count);    }}
  • 还能够通过@ParameterizedTest来进行参数化测试。
/** * JUnit其余测试 * Created by macro on 2022/10/10. */@ExtendWith(SpringExtension.class)public class OtherTest {    private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleTest.class);    @ParameterizedTest    @ValueSource(ints = {1,2,3})    public void parameterizedTest(int a){        LOGGER.info("parameterizedTest():a={}",a);    }}
  • 运行以上测试方法后,具体测试后果如下。

我的项目实战

下面介绍了Spring Boot Test的根本应用,上面咱们联合我的项目来应用下它。

Dao层测试

如果咱们的我的项目须要对数据拜访层Dao中的办法进行测试的话,间接注入Mapper接口,在测试方法中间接调用即可,这里对依据ID查问品牌的Mapper办法进行测试。

/** * Dao层办法测试 * Created by macro on 2022/10/11. */@SpringBootTestpublic class MapperTest {    private static final Logger LOGGER = LoggerFactory.getLogger(MapperTest.class);    @Autowired    private PmsBrandMapper brandMapper;    @Test    void testGetById(){        long id = 6;        PmsBrand pmsBrand = brandMapper.selectByPrimaryKey(id);        LOGGER.info("brand name:{}",pmsBrand.getName());        Assertions.assertEquals("小米",pmsBrand.getName());    }}

Service层测试

对业务层Service中的办法测试也是一样的,间接注入Service接口,在测试方法中间接调用即可,这里对依据ID查问品牌的Service办法进行测试。

/** * Service层办法测试 * Created by macro on 2022/10/11. */@SpringBootTestpublic class ServiceTest {    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceTest.class);    @Autowired    private PmsBrandService brandService;    @Test    void testGetById(){        long id = 6;        PmsBrand pmsBrand = brandService.getBrand(id);        LOGGER.info("brand name:{}",pmsBrand.getName());        Assertions.assertEquals("小米",pmsBrand.getName());    }}

Controller层测试

对于Controller层办法进行测试,有时咱们须要模仿申请,应用MockMvc即可,这里模仿测试下分页查问品牌列表的接口。

/** * Controller层办法测试 * Created by macro on 2022/10/11. */@SpringBootTest@AutoConfigureMockMvcpublic class ControllerTest {    @Autowired    private MockMvc mockMvc;    @Test    void mvcTest() throws Exception{        //模仿发送一个申请拜访分页查问品牌列表的接口        mockMvc.perform(MockMvcRequestBuilders.get("/brand/list") //设置申请地址                .param("pageNum","1") //设置申请参数                .param("pageSize","5"))                .andExpect(MockMvcResultMatchers.status().isOk()) //断言返回状态码为200                .andDo(MockMvcResultHandlers.print()) //在控制台打印日志                .andReturn(); //返回申请后果    }}

因为咱们抉择了在控制台输入日志,控制台将输入如下信息。

总结

明天带大家体验了一把Spring Boot Test,作为Spring Boot官网测试框架,的确性能很弱小。因为其次要基于JUnit 5,和JUnit 5的用法基本一致。应用它进行单元测试,无需启动整个我的项目,更快更好用!

参考资料

JUnit 5官网文档:https://junit.org/junit5/docs...

我的项目源码地址

https://github.com/macrozheng...