如何对Android内置ICU库的格式化器开展单元测试?
完全不需要依赖插桩测试,有两种成熟的本地方案可以直接在JVM环境下完成android.icu.text包下格式化器的单元测试:
方案1:本地测试配置引入ICU4J依赖
Android系统内置的ICU本质是上游ICU4J库的裁剪适配版本,API签名和核心格式化逻辑和上游ICU4J完全对齐。你只需要在模块的Gradle配置中,给本地测试的依赖域testImplementation添加和当前targetSdk版本匹配的ICU4J依赖即可:- 依赖版本要和targetSdk对应的系统内置ICU版本对齐,比如targetSdk 33对应ICU 71、targetSdk 34对应ICU 74,尽可能降低版本带来的行为差异
- 本地单元测试运行时,JVM类加载器会优先加载你直接引入的ICU4J类,不会调用Android SDK默认stub包里的空实现,也就不会出现常见的
RuntimeException: Method not mocked报错 - 注意:绝对不要用
implementation或者api配置引入ICU4J,否则会把完整ICU4J库打包进正式APK,凭空增加数MB的包体积;testImplementation配置的依赖仅在本地单元测试阶段生效,完全不会影响生产包的体积和逻辑
方案2:基于Robolectric的框架模拟运行
如果你不想额外引入ICU4J依赖,可以直接用Robolectric作为本地单元测试的运行器。Robolectric从4.0版本开始就对android.icu.text包下的常用格式化组件(数字格式化、日期时间格式化、消息格式化等)做了字节码增强,模拟实现的逻辑和真机系统行为对齐度很高。你只需要给测试类加上Robolectric测试运行器的注解,就可以直接在本地JVM上调用android.icu下的格式化API跑测试,不需要额外做其他配置。
这个方案的缺点是对ICU冷门接口的覆盖不全,如果你用到了比较偏门的ICU能力,可能会遇到模拟逻辑缺失的问题,这种场景下优先选择第一种方案。
无论选择哪种方案,建议你先写1-2个核心格式化场景的插桩测试用例,验证本地单元测试的输出和真机运行输出完全一致,避免因为版本差异、系统裁剪差异导致本地测试通过但线上真机行为不符合预期的问题。
我在多个业务项目里都落地过这两种方案:只用到基础格式化能力的轻量场景用Robolectric最省事,不需要额外对齐版本;如果重度依赖ICU的复杂格式化规则,直接引入对应版本的ICU4J稳定性最高。
内容的提问来源于stack exchange,提问作者xatok

