如何确保Laravel升级前已覆盖所有Laravel函数调用测试?
我正在给一个基于旧版Laravel的项目做自定义升级,要升到当前最新的Laravel版本。这个项目原本没有单元测试,为了降低升级后功能崩溃的风险,我打算在升级前先写测试。但项目规模太大,要做到100%测试覆盖太费时间,所以我只想写能覆盖调用Laravel函数的代码的测试(允许覆盖更多代码,只要所有Laravel函数调用都被覆盖就行),而且每个Laravel函数只需要测一次——也就是说,如果某个类里的某个函数调用了某个Laravel函数,且这个调用已经被测试覆盖,那其他调用同一个Laravel函数的代码就不用再测了。
我的问题是:怎么确保我已经达到这个目标?
我试过/考虑过的方案:
- 没找到能显示未覆盖代码行是否和已覆盖代码行调用完全相同Laravel函数的覆盖率报告工具;
- 考虑过用IDE的代码覆盖率扩展,能查看函数声明是否被覆盖,但这只能显示底层函数有没有运行,没法证明是项目代码调用导致的覆盖。
1. 自定义覆盖率分析脚本
利用PHPUnit生成的clover.xml或coverage.php覆盖率数据,写个简单脚本做以下操作:
- 用正则匹配遍历项目所有代码,提取调用Laravel核心函数/门面的位置(比如
Auth::user()、DB::table()、collect()这类); - 对比覆盖率数据,标记哪些Laravel函数的调用已被测试覆盖;
- 生成清单,列出所有未被任何测试覆盖的Laravel函数调用。
比如可以用PHP解析clover.xml,提取已覆盖的代码行,再和项目中所有Laravel函数调用的位置做比对,找出遗漏项。
2. 用Mockery监听Laravel函数调用
在测试中借助Mockery监听Laravel门面或核心类的方法调用,记录被调用的函数名:
- 比如监听
DB::select,每次被调用就把这个方法名写入日志文件; - 跑完所有测试后,去重日志里的Laravel方法,再和项目中实际用到的Laravel方法做比对,找出没被覆盖的。
示例代码:
Mockery::spy(\Illuminate\Support\Facades\DB::class) ->shouldReceive('select') ->andReturnUsing(function () { file_put_contents(storage_path('laravel_calls.log'), "DB::select\n", FILE_APPEND); return []; });
3. 静态分析+覆盖率结合
先用静态代码分析工具(比如PHPStan、Psalm)扫描整个项目,提取所有调用Laravel核心API的位置和对应函数名,生成完整的Laravel函数调用清单;
再把这个清单和PHPUnit的覆盖率报告关联,找出哪些Laravel函数的调用未被测试覆盖。
比如可以给PHPStan写个自定义规则,专门收集项目中对Laravel门面、辅助函数的调用,导出为JSON文件后和覆盖率数据做比对。
4. 手动标记已覆盖调用
在测试覆盖某个Laravel函数调用后,在对应代码行加注释标记(比如// @covered-laravel-call DB::select),然后用脚本扫描整个项目,检查所有Laravel函数调用是否都有对应的标记。这种方法虽然偏手动,但适合关键函数的覆盖验证。
内容的提问来源于stack exchange,提问作者Sam Coppock

