项目里的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的标准用法
集成Spring(The SpringJUnitConfig and SpringJUnitWebConfig Annotations in Spring 5 | Baeldung)
- 使用JUnit5的拓展模型特性,@ExtendWith(SpringExtension.class),可以使用Spring的上下文装载功能,而不用去使用重量级的@SpringBootTest
集成Mockito (Mockito and JUnit 5 - Using ExtendWith | Baeldung)
- 引入JUnit5和Mockito的maven依赖
- 配置Surefire Plugin,使得测试代码都运行在新的JUnit平台上
- 有必要兼容JUnit4的测试代码的话,还需加入JUnit5 vintage-engine的maven依赖
- @ExtendWith(MockitoExtension.class), 集成Mockito,可以使用@Mock, @Spy, @InjectMocks等注解,方便我们写UT
JUnit 4 VS JUnit 5
- 注解的区别
注解的使用区别
- 常用的
//Exception @Test(expected = Exception.class) // JUnit4 @Test(timeout = 1) // JUnit4 //TimeOut Assertions.assertThrows(); // JUnit5 Assertions.assertTimeout(1); //JUnit5
@RunWith 和 @ExtendWith(最大特性差异)
@RunWith 用于将测试上下文与其他框架集成或更改 JUnit 4 中测试用例中整体执行流程
而在 JUnit 5 中,我们现在可以使用 @ExtendWith 注解来提供类似的功能
@RunWith(SpringJUnit4ClassRunner.class) public class SpringExtensionTest { /* JUnit4 */ } @ExtendWith(SpringExtension.class) public class SpringExtensionTest { /* JUnit5 */ }
为什么要使用JUnit5
粒度更细
JUnit 4 有一些明显的限制:整个框架包含在一个 jar 库中,即使只需要特定功能,也需要导入整个库
而在 JUnit 5 中,我们获得了更多的粒度,并且可以只导入必要的内容同时运行多个运行器
一个测试运行器一次只能在 JUnit 4 中执行测试(例SpringJUnit4ClassRunner 或 Parameterized )
而在 JUnit 5 允许多个运行器同时工作赶上JDK8的浪潮
这个大家写过Java的,懂得都懂
升级
将@SpringBootTest 以及 @RunWith(SpringRunner.class 或者 SpringJUnit4ClassRunner)移除,换成JUnit5拓展新特性 @ExtendWith(SpringExtension.class)
Spring Boot 提供了
@SpringBootTest
注解,我们可以使用它来创建一个应用程序上下文,其中包含所有上述测试类型所需的所有对象。但是请注意,过度使用@SpringBootTest
可能会导致测试套件运行时间过长SpringRunner 继承自 SpringJUnit4ClassRunner
将所有org.junit.的 import,都换成 org.junit.jupiter.
优化思路
- 多使用Mockito轻量级的工具 去写UT
@ExtendWith(MockitoExtension.class)
需要用到Spring Context,就可使用 @ExtendWith(SpringExtension.class) - 在代码层面可以将 @Autowired换成,构造器注入,与Spring解耦合,不然写UT需要注入Bean的时候,就不得不使用Spring容器
- 少使用@MockBean,@SpyBean这些Spring提供的注释,虽然它可以帮我们轻松使用 Mockito 的Mock功能。让Spring Boot 功能很容易包含在我们的测试中,但我们应该意识到成本:每个测试都可能创建一个新的应用程序上下文,这可能会显着增加测试套件的运行时间,而这恰恰也就是你UT跑得慢的原因!
除了在写集成测试时用到@SpringBootTest,其他均不用,不得已要使用的话,也尽可能尽着 少加载Bean的目标,去写code,越少bean加载,速度就越快
- classes 指定需要 装载的 class
- webEnvironment不使用时关掉(不过好像默认是关的)
- 升级JUnit5
说在最后
UT这种东西,当然是覆盖率和质量越高越好,但也取决于项目的赶工程度,又想马儿跑,有不给马儿吃草,这种本就不现实
但作为开发人员,大家要对技术有一定了解,不要老是copy前人代码的改改改,因为别人的不一定是对的,也不一定是最好的,只能说明,它是稳定且不怎么出大问题的
最后 好文推荐:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。