项目里的UT越来越慢,怎么办?

项目里的UT越来越慢,怎么办?

JUnit是一个Java语言的单元测试框架。它由Kent
Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个。
JUnit有它自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试的工具。
它已经发展有20余年历史了

现在我们的项目在Jenkins流水线上每次部署时,随着code越来越多,UnitTest这部分Stage也每次都跑得最慢,怎么可以加快速度呢?

可以试着从code层面去尝试 refactor,比如将Junit4升级到更好效率更快的Junit5

JUnit5

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

JDK Version >= 8 (而 JUnit4是要求 JDK Version >= 5)

JUnit平台 它定义了TestEngine用于开发在平台上运行的新测试框架的API
JUnit Jupiter 它具有所有新的junit注释和TestEngine实现,以运行使用这些注释编写的测试
JUnit Vintage 支持在JUnit 5平台上运行JUnit 3和JUnit 4编写的测试

JUnit5的标准用法

  1. 集成Spring(The SpringJUnitConfig and SpringJUnitWebConfig Annotations in Spring 5 | Baeldung

    1. 使用JUnit5的拓展模型特性,@ExtendWith(SpringExtension.class),可以使用Spring的上下文装载功能,而不用去使用重量级的@SpringBootTest
  2. 集成Mockito (Mockito and JUnit 5 - Using ExtendWith | Baeldung

    1. 引入JUnit5和Mockito的maven依赖
    2. 配置Surefire Plugin,使得测试代码都运行在新的JUnit平台上
    3. 有必要兼容JUnit4的测试代码的话,还需加入JUnit5 vintage-engine的maven依赖
    4. @ExtendWith(MockitoExtension.class), 集成Mockito,可以使用@Mock, @Spy, @InjectMocks等注解,方便我们写UT

JUnit 4 VS JUnit 5

  1. 注解的区别
    项目里的UT越来越慢,怎么办?_第1张图片
  2. 注解的使用区别

    1. 常用的
    //Exception
    @Test(expected = Exception.class) // JUnit4
    @Test(timeout = 1) // JUnit4
    
    //TimeOut
    Assertions.assertThrows(); // JUnit5
    Assertions.assertTimeout(1); //JUnit5
    1. @RunWith 和 @ExtendWith(最大特性差异)

      @RunWith 用于将测试上下文与其他框架集成或更改 JUnit 4 中测试用例中整体执行流程
      而在 JUnit 5 中,我们现在可以使用 @ExtendWith 注解来提供类似的功能
    @RunWith(SpringJUnit4ClassRunner.class)
    public class SpringExtensionTest {
        /* JUnit4 */
    }
    
    @ExtendWith(SpringExtension.class)
    public class SpringExtensionTest {
        /* JUnit5 */
    }

为什么要使用JUnit5

  1. 粒度更细

    JUnit 4 有一些明显的限制:整个框架包含在一个 jar 库中,即使只需要特定功能,也需要导入整个库
    而在 JUnit 5 中,我们获得了更多的粒度,并且可以只导入必要的内容
  2. 同时运行多个运行器

    一个测试运行器一次只能在 JUnit 4 中执行测试(例SpringJUnit4ClassRunner 或 Parameterized )
    而在 JUnit 5 允许多个运行器同时工作
  3. 赶上JDK8的浪潮

    这个大家写过Java的,懂得都懂

升级

  1. 将@SpringBootTest 以及 @RunWith(SpringRunner.class 或者 SpringJUnit4ClassRunner)移除,换成JUnit5拓展新特性 @ExtendWith(SpringExtension.class)

    Spring Boot 提供了@SpringBootTest注解,我们可以使用它来创建一个应用程序上下文,其中包含所有上述测试类型所需的所有对象。但是请注意,过度使用@SpringBootTest 可能会导致测试套件运行时间过长

    SpringRunner 继承自 SpringJUnit4ClassRunner

  2. 将所有org.junit.的 import,都换成 org.junit.jupiter.

    (Migrating from JUnit 4 to JUnit 5 | Baeldung)

优化思路

  1. 多使用Mockito轻量级的工具 去写UT@ExtendWith(MockitoExtension.class)
    需要用到Spring Context,就可使用   @ExtendWith(SpringExtension.class)
  2. 在代码层面可以将 @Autowired换成,构造器注入,与Spring解耦合,不然写UT需要注入Bean的时候,就不得不使用Spring容器
  3. 少使用@MockBean,@SpyBean这些Spring提供的注释,虽然它可以帮我们轻松使用 Mockito 的Mock功能。让Spring Boot 功能很容易包含在我们的测试中,但我们应该意识到成本:每个测试都可能创建一个新的应用程序上下文,这可能会显着增加测试套件的运行时间,而这恰恰也就是你UT跑得慢的原因!
  4. 除了在写集成测试时用到@SpringBootTest,其他均不用,不得已要使用的话,也尽可能尽着 少加载Bean的目标,去写code,越少bean加载,速度就越快

    • classes 指定需要 装载的 class
    • webEnvironment不使用时关掉(不过好像默认是关的)
  5. 升级JUnit5

说在最后

UT这种东西,当然是覆盖率和质量越高越好,但也取决于项目的赶工程度,又想马儿跑,有不给马儿吃草,这种本就不现实

但作为开发人员,大家要对技术有一定了解,不要老是copy前人代码的改改改,因为别人的不一定是对的,也不一定是最好的,只能说明,它是稳定且不怎么出大问题的

最后 好文推荐:

你可能感兴趣的:(单元测试junit5)