用户从相册选中一张图片后,应用可能要读取方向信息、生成缩略图、压缩原图并上传;视频还会增加时长、编码和文件大小分支。只在开发机里手动点一次,无法证明下一次构建仍能处理同一组输入。更稳妥的做法,是把媒体文件作为测试夹具纳入仓库,在云端 Mac 上重置独立模拟器,再用 simctl addmedia 注入相册。
先定义要验证的边界
这类测试应聚焦应用与系统相册之间的接口,而不是自动操作系统相册应用。建议至少覆盖四条路径:
- 应用能发现预期数量的图片和视频。
- 选择器返回后,文件类型、像素尺寸和视频时长符合预期。
- 压缩或上传任务使用原始资源,而不是偶然取得的预览图。
- 不支持的格式、超大文件和权限变化能进入明确的错误分支。
simctl addmedia 适合验证模拟器中的读取和处理链路,但不能代替相机采集、设备专用编码及真实存储压力测试。把这些边界写进测试说明,失败时就不会把模拟器限制误判成产品缺陷。
回归测试的目标不是塞入尽可能多的素材,而是让每个素材都对应一个可以命名、重复和诊断的行为。
准备小而稳定的媒体夹具
在仓库中建立 Tests/Fixtures/Media,只提交测试所需的最小文件。文件名应表达预期用途,不要使用相机自动生成的名称。
| 文件 | 用途 | 主要断言 |
|---|---|---|
portrait.jpg |
带方向信息的竖图 | 方向修正后宽高正确 |
transparent.png |
含透明通道的图片 | 导出后透明度未丢失 |
short.mov |
短视频 | 时长与媒体类型正确 |
invalid.txt |
非媒体文件 | 注入步骤主动拒绝 |
同时保存 SHA-256 清单,防止夹具被图片工具无意重写:
cd Tests/Fixtures/Media
shasum -a 256 portrait.jpg transparent.png short.mov > SHA256SUMS
shasum -a 256 -c SHA256SUMS
不要在任务运行时重新编码夹具。不同系统版本的编码器可能写入不同元数据,使问题从“应用行为变化”变成“输入已经变化”。确实需要动态文件时,应把生成脚本、参数和生成后的摘要一并记录。
为每个任务隔离模拟器
共享一个长期运行的模拟器会留下相册资产、权限记录和后台进程。最简单的基线是由调度层传入 DEVICE_UDID,任务开始后关机、抹除并等待启动完成:
set -euo pipefail
: "${DEVICE_UDID:?DEVICE_UDID is required}"
: "${BUNDLE_ID:?BUNDLE_ID is required}"
xcrun simctl shutdown "$DEVICE_UDID" 2>/dev/null || true
xcrun simctl erase "$DEVICE_UDID"
xcrun simctl boot "$DEVICE_UDID"
xcrun simctl bootstatus "$DEVICE_UDID" -b
xcrun simctl privacy "$DEVICE_UDID" reset photos "$BUNDLE_ID" || true
xcrun simctl privacy "$DEVICE_UDID" grant photos "$BUNDLE_ID"
模拟器型号和系统版本也要由任务配置固定,不能只写 name=iPhone 让 Xcode 自行挑选。并行任务必须使用不同 UDID;否则一个任务执行 erase 时,另一个任务可能正在跑测试。
权限测试应拆成两组:主流程预先授予相册权限,验证媒体处理;拒绝权限流程单独执行 revoke,只断言应用提示和恢复入口。不要让系统弹窗是否出现决定测试成败。
注入素材并执行定向测试
注入前先校验扩展名和摘要,再把受支持文件一次性交给 addmedia:
FIXTURES="$PWD/Tests/Fixtures/Media"
shasum -a 256 -c "$FIXTURES/SHA256SUMS"
xcrun simctl addmedia "$DEVICE_UDID" \
"$FIXTURES/portrait.jpg" \
"$FIXTURES/transparent.png" \
"$FIXTURES/short.mov"
xcodebuild test \
-workspace Demo.xcworkspace \
-scheme Demo \
-destination "platform=iOS Simulator,id=$DEVICE_UDID" \
-only-testing:MediaImportTests \
-resultBundlePath "$PWD/Artifacts/MediaImport.xcresult"
addmedia 返回成功只说明命令接受了文件,不代表应用已经看见正确资产。测试代码应等待相册查询达到预期数量,并设置有限超时。断言优先使用媒体类型、像素尺寸、时长范围和业务生成结果,不要依赖系统相册中的显示顺序,因为导入时间与资源创建时间可能不同。
如果应用会上传文件,可把网络层替换为本地测试实现,记录收到的 MIME 类型、字节数和摘要。这样既能确认读取的是原始资源,也不会把外部网络波动混入回归结果。
让失败结果可以复查
失败任务至少保留三类证据:xcresult、夹具摘要和本次设备信息。可以额外输出当前可用模拟器列表,但不要收集与问题无关的用户目录内容。
常见误判及处理方式如下:
- 资产数量比预期多:模拟器没有在任务前抹除,或多个任务复用了同一 UDID。
- 测试偶尔查不到视频:导入后立即查询,没有等待照片资料库完成更新。
- 图片宽高颠倒:代码读取像素尺寸时忽略了方向元数据。
- 本地通过、CI 失败:测试依赖了未提交文件、默认权限或模糊的 destination。
- 上传摘要变化:应用重新编码了资源,应分别记录输入摘要与上传体摘要。
任务结束时关停模拟器;若设备由当前任务临时创建,则直接删除。长期设备也应在下一次任务前重新 erase,不要依赖逐项删除相册内容。最终检查项可以收敛为:夹具摘要一致、UDID 独占、系统版本固定、权限状态显式、导入数量可等待、结果包已归档。做到这些,媒体导入失败才具备稳定输入和可复查现场。
常见问题
simctl addmedia 能否替代真机相册测试?
不能完全替代。它适合验证模拟器中的媒体发现、选择、读取和上传流程;相机采集、设备特有编码及真实存储压力仍应安排真机补测。
如何避免多次运行后相册素材不断累积?
每个任务使用独立模拟器,并在注入前执行关机和 erase;如果必须复用设备,则先核对资产数量并在任务结束后销毁该设备。
在独享 Apple Silicon 物理节点上执行下一次构建
选择租期与节点区域,核对 Mac Mini M4、16GB RAM、256GB SSD 和应付 USD 金额后提交订单。