• 【Maven】本地执行一个模块的UT失败,但是线上能执行成功


    背景

    在一个工程项目中,往往我们都需要针对新写的代码补充 UT.
    基于此,我们每次进一次新的代码,比较好的习惯就是用新的 UT 去覆盖或者旧的UT 去覆盖掉当前新写的 代码。

    而就在最近,发现有 UT 不管在本地清理缓存之后,依旧执行失败,但是在线上却都能每次都成功。
    并且两边的 UT 执行都是串行的,所以可以很确定的说,这个 UT 肯定在本地有上下文影响的。

    原因定位

    串行执行,但是顺序不一样?

    在确定了串行执行的之后,发现,既然都是串行的,线上和本地的电脑执行的 maven 版本也都对齐了都情况下。

    对齐 maven 版本,是为了避免再次遇到奇奇怪怪的问题,在定位问题的时候,如果没有太多的上下文,那么对齐测试步骤和使用工具版本是非常有必要的。

    理论上,两边的执行case 的顺序也应该是一样的。
    但是很不幸,使用脚本快速确认两边执行的测试用例的顺序是不一样。
    预期失败的 case 是在本地最后一个执行的,而在线上 却是在中间就执行了。

    万幸的是,确定了顺序是不一样,那么就很快确定,其实影响了case 范围我们也能确定下来。

    排除了线上能执行通过的前置的那些case,那么剩下的case 肯定就是能影响到了。

    到底是哪个case 影响到了?

    确定了影响的范围的 case 到底是哪些呢?是一个还是两个?

    一个简单的做法其实就是二分法,将剩下的 影响的case 一半 disable或者说是skip 掉,然后重跑,逐渐缩小其范围,当然我们可以写脚本去触发 ut 执行即可。

    最终,确定了影响的case 竟然是这样写代码!

    @Test
    public void testA() {
    	...
    	MockedStatic<StaticUtils> utilities = Mockito.mockStatic(StaticUtils.class));
    	utilities.when(StaticUtils::name).thenReturn("Eugen");
    	assertThat(StaticUtils.name()).isEqualTo("Eugen")
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    有小伙伴看出是什么问题了吗?!

    对,乍一看好像什么都没错,但是实际上这个是有大问题的!

    因为根据 Maven 官方一些使用文档,着重提醒了如下内容!
    参考文档:
    maven 使用手册:关于 static mocks
    Mocking Static Methods With Mockito

    As previously mentioned, since Mockito 3.4.0, we can use the Mockito.mockStatic(Class classToMock) method to mock invocations to static method calls. This method returns a MockedStatic object for our type, which is a scoped mock object.

    Therefore, in our unit test above, the utilities variable represents a mock with a thread-local explicit scope. It’s important to note that scoped mocks must be closed by the entity that activates the mock. This is why we define our mock within a try-with-resources construct so that the mock is closed automatically when we finish with our scoped block.

    意思简单翻译下就是:如果要用 mock static 那么请注意使用 try-with-resources 的方式,不要让其影响到整个测试流程!

    @Test
    public void testA() {
    	...
    	try (MockedStatic<StaticUtils> utilities = Mockito.mockStatic(StaticUtils.class))) {
    		utilities.when(StaticUtils::name).thenReturn("Eugen");
    		assertThat(StaticUtils.name()).isEqualTo("Eugen")
    	}
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    总结

    这个 mock static 影响的非常大,但是藏着又特别深,在非常多的 case 当中去找到影响的 case 是非常费力又不讨好的事情。
    所以,千万谨记,如果要用相关的 测试方式,请查看人家的官网测试手册给到的建议!!!

    番外

    为什么线上的 maven 和 本地的maven 的执行 ut case 顺序不一样?
    原因在于,线上的执行命令修改了,并且用的排序方式是使用执行测试的方法名字典序排列。
    而本地执行顺序是以执行方法类的字典序排列。
    这就是一开始的差异点。

  • 相关阅读:
    【面试必备】我跟面试官聊了一个小时线程池!
    第一章 数据分析与可视化概述
    飞书API(5):查看多维表 28 种数据类型的数据结构
    全栈开发性能优化基础第二单元日考技能
    pytorch导出为onnx,使用onnxruntime进行推理
    vue3的基本特性和底层原理
    【氮化镓】液态Ga在GaN(0001)和(0001̅)表面上的三维有序排列随温度的变化
    jmeter集成kafka测试
    ND协议——无状态地址自动配置 (SLAAC)
    HTML网页设计【足球科普】学生DW静态网页设计
  • 原文地址:https://blog.csdn.net/mukvintt/article/details/133793004