单元测试不能直接用真实视频文件,因其慢、不可靠、难并行;应mock封装层(如videoprocessor)依赖的ffmpeg实例,严格模拟ffprobe元数据结构,并显式配置异常以覆盖失败场景。

为什么不能直接用真实视频文件跑单元测试
因为会慢、不可靠、难并行——读写磁盘IO耗时,临时文件残留污染后续测试,不同环境路径权限不一致导致file_exists()或fopen()随机失败。单元测试要验证的是「视频处理逻辑是否正确」,不是「Linux服务器上ffmpeg装没装好」。
Mock Ffmpeg\FFMpeg 实例的关键点
别 Mock FFMpeg 类本身(它构造时会尝试加载二进制),而是 Mock 你封装的视频服务类(如 VideoProcessor)所依赖的 FFMpeg 实例;若必须 Mock 底层,得用 $this->createMock(FFMpeg::class) 并禁用构造逻辑。
- 确保
FFMpeg::fromDisk()返回一个能链式调用open()的 mock 对象 -
open()必须返回一个支持filters()->resize()和save()的 mock 实例 - 用
$mock->expects($this->once())->method('save')->with($this->stringContains('thumb_'))验证输出路径是否符合预期 - 不要在 mock 中模拟 ffmpeg 命令执行细节——那是集成测试的事
构造可复用的视频元数据 Mock 数据
真实 ffprobe 返回的是嵌套数组,比如 ['streams'][0]['width'],mock 时必须严格匹配结构和类型,否则业务代码里 $meta['streams'][0]['width'] > 1920 会报 Notice 或 PHP 8+ 类型错误。
- 用
$this->createStub(FFProbe::class)+willReturn()返回预设数组,比createMock()更轻量 - 关键字段不能省:至少包含
streams(含codec_type、width、height)、format(含duration、size) - 测试不同分支时,改
streams[0]['codec_type']为'audio'或'video',验证跳过逻辑是否生效 - 避免用
json_encode()模拟输出再json_decode()—— 多余且易错
测试视频转码失败场景的惯用手法
真实 ffmpeg 进程崩溃时抛 Ffmpeg\Exception\RuntimeException,但 mock 不会自动触发异常,必须显式配置。
- 用
$mockEncoder->method('save')->willThrowException(new RuntimeException('Encoding failed')) - 在被测方法里用
try/catch捕获该异常,并断言返回值或日志行为 - 别只测「成功路径」——视频处理失败才是线上高频问题
- 注意:PHP 8.1+ 要求异常类存在且可 autoload,确保
composer.json的autoload-dev包含对应路径
is_writable()、unlink())、外部命令(exec())、第三方库(FFMpeg)三层依赖。Mock 只解决其中一层,剩下两层要么用内存文件系统(如 phpvfscomposer/phpvfs),要么改用依赖注入把它们也抽成接口——否则测试永远在补洞。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











