关于单元测试:项目里的UT越来越慢怎么办

43次阅读

共计 2634 个字符,预计需要花费 7 分钟才能阅读完成。

我的项目里的 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. 注解的区别
  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 前人代码的改改改,因为他人的不肯定是对的,也不肯定是最好的,只能阐明,它是稳固且不怎么出大问题的

最初 好文举荐:

  • Mockito Tutorial | Baeldung
  • Learn JUnit | Baeldung

正文完
 0