如何对包含多类依赖的PHP非类CLI运行函数进行单元测试
PHP CLI常驻脚本单元测试可行方案
针对你提供的常驻CLI脚本,可按照以下两个维度的方案实现测试,同时完成所有外部依赖的Mock:
最小侵入式测试方案(无需大规模修改原有代码)
适合暂时无法重构原有业务代码的场景,改动量极小:
- 第一步先封装脚本执行入口,避免文件加载即执行:在原有脚本最外层增加执行判断,把所有业务逻辑包裹到独立函数内
测试时提前定义// 原有run_task.php文件头部新增代码 if (!defined('RUN_TASK_TEST_MODE')) { runTaskEntry(); } function runTaskEntry() { // 把你原有全部脚本代码放到该函数内 }RUN_TASK_TEST_MODE常量,引入文件后可自主调用执行逻辑,不会触发自动运行。 - 单例类Mock:通过反射替换单例类的私有实例属性,无需修改单例原有代码即可注入Mock对象,示例如下:
按照同样逻辑完成// 以Mock settings单例为例 $mockSettings = $this->createMock(settings::class); $mockSettings->expects($this->once())->method('load')->with('main'); // 反射修改单例实例 $ref = new ReflectionClass(settings::class); $instanceProp = $ref->getProperty('instance'); $instanceProp->setAccessible(true); $instanceProp->setValue(null, $mockSettings);db、mongo、\publish\Log、\publish\JobEngine等所有依赖的Mock。 - 无限循环规避:用命名空间函数覆盖的方式替换原生
usleep实现,同时可以在测试时临时修改循环计数阈值,比如将1000次退出改为2次退出,避免测试死循环。 - 逻辑验证点覆盖:
- 信号处理:手动调用
gracefullExit函数,验证GRACEFULL_EXIT环境变量被正确设置为1,脚本可正常退出且退出码为0 - 异常捕获:Mock
\publish\JobEngine::runTask()使其抛出异常,验证异常被捕获,不会终止脚本运行,error_log有对应错误输出 - 自动重启:验证循环次数达到阈值后脚本正常退出
- 信号处理:手动调用
可测试性重构方案(长期维护推荐)
如果允许调整原有代码,重构后测试成本会大幅降低:
- 把所有逻辑拆分到独立的
RunTask类中,初始化、信号处理、主循环分别封装为独立方法 - 所有外部依赖(settings、db、mongo、日志、任务引擎)全部通过构造函数注入,替换原有硬编码的单例调用、静态调用
- 把
usleep、getenv、putenv等系统调用也封装为可注入的工具类,测试时直接Mock工具类即可,无需处理全局函数覆盖
重构完成后测试时直接传入所有Mock后的依赖对象即可,测试用例编写更简单,可维护性更高。
内容的提问来源于stack exchange,提问作者banshee
相关产品推荐
相关产品推荐

