一、AOSP组件Mock回放概述:从一次“翻车”说起

先聊聊我最早接触Mock回放时的一次“翻车”吧。

那时候我刚接手一个AOSP的媒体模块测试,跑自动化用例经常挂,而且只在凌晨CI里挂,本地怎么都复现不了。那时候我写的测试都是实打实去调底层硬件,摄像头、音频DSP都得上。有一天我排查日志发现,CI环境里的硬件时序和我本地不一样,导致组件状态错过了某个窗口期。说白了,我测的压根不是“组件逻辑”,而是“硬件时序”。

那之后我才真正明白:对AOSP这类庞大、多进程、依赖硬件的系统来说,测错对象等于白测。所以,我们需要Mock和回放。

1.1 到底什么是Mock?

Mock不是造假。在AOSP里,Mock的本质是替身演员。

你原本的组件要调用CameraService、Sensor HAL、AudioFlinger。但在测试环境里,这些真实服务要么跑不起来,要么跑起来不稳定。Mock就是做一个“长得一模一样但我说了算”的替身,接管组件的外部依赖。

核心观点:Mock隔离了组件与外部世界,让你只测组件内部状态机。

我个人习惯把Mock分为三类,在AOSP里最常用的是前两种:

类型特点AOSP典型场景
Stub直接返回固定值,没有行为逻辑给一个Service返回固定Binder对象
Spy部分真实、部分模拟,能记录调用监听某个回调是否被触发了两次
Fake有轻量级真实实现,但不依赖硬件内存版FileSystem替代真实存储

你想想看,你在测一个DisplayManagerService的窗口切换逻辑。如果你是真去开关屏幕,测一次要两秒,还有硬件损坏风险。但如果你Mock了一个DisplayAdapter,让它模拟“收到屏幕关闭通知”,那测试跑一次可能只要两毫秒。这就是效率。

一个小提示:在AOSP的TradeFed或Atest框架里,Mock常用Mockito搭配Android的Instrumentation环境。
比如:@Mock CameraManager mockManager; 加上 MockitoAnnotations.initMocks(this);

1.2 那“回放”又是什么?

回放,说白了就是把真实场景里抓到的交互记录,原封不动再放一遍。

为什么需要这个?因为AOSP组件之间的交互太复杂了。你今天手动写Mock,你只能假设数据的格式和你之前想的一样。但真实的系统里,数据顺序、时间戳、并发线程都可能和你想象的完全不同。

回放的典型流程:

  1. 第一次运行:开启录制模式,所有调用的参数、返回、异常、时间戳都被记录下来。
  2. 之后测试:不再调用真实接口,而是从录制文件中读取“之前录好的响应”,直接返回给被测组件。
  3. 做回归或对比测试:如果组件行为变了,回放会导致结果不一致,捕获回归Bug。

举个例子,我测SurfaceFlinger的BufferQueue状态机。我录制了一次完整的“app提交buffer → 合成 → 释放”流程。之后我把版本升级了,再放一遍这个录制,结果组件在第3步报错了。这说明新版本改了某个时序处理,而这个时序我之前根本没注意到。这就很值钱。

曾经踩过的一个坑:回放文件的版本兼容问题。有一次我换了一个AOSP大版本,Binder接口的序列化格式变了,旧的回放文件直接反序列失败。所以,回放文件一定要和被测版本强绑定,不能跨版本复用。

1.3 为什么需要Mock + 回放?

单独用Mock,你是在“猜”外部行为;单独用回放,你是在“放”真实行为。

把两者一结合,就是 先用回放抓真实数据,再用Mock把这些数据注入到测试里。这样做的好处相当明显:

  • 数据真实:不是开发者编造的数据,而是从系统录制下来的真正交互。
  • 环境可控:不依赖硬件,CI里能稳定复现。
  • 回归自动化:换版本后重新跑一遍回放,立刻看到改动的影响。

我见过很多团队在AOSP开发时,只做纯单元测试,覆盖率挺高,但走到集成测试和系统测试就炸。为什么?因为Mock不准,数据是编的。一旦用了Mock回放,你就能在开发者桌面复现最复杂的环境问题。

Mock与回放核心知识体系图 AOSP组件Mock回放知识体系 组件测试的核心痛点 Mock(模拟替身) 回放(数据重演) Stub(固定返回) Spy(记录调用) Fake(轻量实现) 全量回放 条件回放 增量回放 Mock + 回放 组合使用 环境可控 + 数据真实 + 回归自动化

从上面这张图你大概能看明白:Mock和回放不是两个独立概念,而是相辅相成的。左边Mock提供“替身”,右边回放提供“剧本”。没有剧本的替身很容易演砸,没有替身的剧本只能空转。

1.4 我把Mock回放用在哪些场景?

我再具体说说,在AOSP的实际开发中,Mock回放最适合哪些场景:

  • 多版本回归测试:跨AOSP大版本升级时,用回放验证API兼容性。
  • 硬件不可用场景:比如你没有某款手机的硬件外设,但需要测试蓝牙或NFC状态机。
  • 并发竞争条件:你能通过回放精确控制多个Binder调用的时序,制造竞态条件。
  • 测试数据流水线:比如视频编解码链路,每个环节的输入输出都能Mock替换。
一句话总结这章:Mock回放不是为了逃避系统集成测试,而是为了让你能“在可控条件下,无限次验证真实数据流”,从而尽早发现回归问题。