Symfony 命令行测试 5 个场景实战,稳定不翻车
【免费下载链接】nuclei-templatesCommunity curated list of templates for the nuclei engine to find security vulnerabilities.项目地址: https://gitcode.com/GitHub_Trending/nu/nuclei-templates
测一条 Symfony 命令要手动启动内核、执行、捕获输出,五步样板写完还常忘断言退出码。LiipFunctionalTestBundle 命令行测试把这套流程压成一行 runCommand(),verbosity 与交互输入同样替你兜住。下文 5 个场景逐一演示,读完即可写出稳定不翻车的命令测试。
一行 runCommand() 顶替五步样板
手动跑命令测试的完整流程:bootKernel() 起内核,new Application($kernel),find() 找命令,new CommandTester(),execute() 执行——五步写完,断言还没开始。runCommand() 把这五步封装成一行:命令名做第一个参数,参数数组做第二个,返回的 CommandTester 已经捕获好全部输出。
// 手动流程:五步起步 $kernel = self::bootKernel(); $application = new Application($kernel); $command = $application->find('app:my-command'); $tester = new CommandTester($command); $tester->execute(['--force' => true]); // runCommand:一行起步 $tester = $this->runCommand('app:my-command', ['--force' => true]);第三个参数 $reuseKernel 控制同一测试内多次执行命令时是否复用内核,默认不复用,下面场景里还会用到它。
命令跑完断什么:先锁 getStatusCode()
命令跑完,getDisplay() 与 getStatusCode() 要一起断。只盯输出有个隐蔽坑:命令悄悄失败、却打印了相似文本,测试照样绿。退出码 0 表示成功、非零表示失败,断上它是性价比最高的保险。
$tester = $this->runCommand('app:report', ['--format' => 'json']); // 退出码先锁死,再验关键输出文案 self::assertSame(0, $tester->getStatusCode()); self::assertStringContainsString('Report generated', $tester->getDisplay());推荐顺序:先 assertSame 锁退出码,再 assertStringContainsString 验关键文案,别反着来。
verbosity 全局与单条两级怎么配
默认 runCommand() 按 normal 级别执行,不少命令的关键细节要到 verbose 以上才打印。全局提档写在测试环境配置里:
# config/packages/test/liip_functional_test.yaml liip_functional_test: # 合法值:quiet / normal / verbose / very_verbose / debug command_verbosity: debug command_decoration: false配置节点定义在 src/DependencyInjection/Configuration.php,默认值 normal。单条测试想单独提档,setVerbosityLevel() 一行覆盖全局,直接赋值 verbosityLevel 属性也行,是同一回事:
public function testDebugOutput(): void { $this->setVerbosityLevel('debug'); $tester = $this->runCommand('app:my-command'); self::assertStringContainsString('debug detail', $tester->getDisplay()); }💡 分工建议:写 Symfony Command 测试时,团队统一风格走全局 YAML,个别排障用例才 setVerbosityLevel() 临时拉满,别反过来。
verbosity 五档怎么挑:quiet 到 debug 对照
五档级别从静默到全量,先对号入座再定全局值:
| 级别 | 常量 | 对应参数 | 适用场景 |
|---|---|---|---|
| quiet | VERBOSITY_QUIET | 无 | 完全静默,只关心命令成败 |
| normal | VERBOSITY_NORMAL | 默认 | 常规信息,多数命令够用 |
| verbose | VERBOSITY_VERBOSE | -v | 输出额外说明信息 |
| very_verbose | VERBOSITY_VERY_VERBOSE | -vv | 更详细的日志 |
| debug | VERBOSITY_DEBUG | -vvv | 全部调试信息,排障专用 |
选档原则:能低不高。debug 输出又长又慢,只留给真要排障的测试;normal 对绝大多数命令已经够用。
命令会提问时如何喂 setInputs() 输入
交互式命令靠 setInputs() 按提问顺序喂答案,runCommand() 检测到设置了输入会自动把 interactive 模式置为 true:
public function testInteractiveCommand(): void { $this->setInputs(['yes']); $tester = $this->runCommand('app:confirm-command'); self::assertStringContainsString('confirmed', $tester->getDisplay()); }有个容易忽略的设计:输入在首次执行后会被清空,下一次 runCommand() 回到默认值。这正好贴合真实交互——每条命令独立应答,不会拿残留答案答错下一题。
CI 日志变乱码?关掉 ANSI 装饰
CI 控制台和日志文件不渲染颜色,命令输出里的 ANSI 转义字符会变成乱码,基于文本的断言也可能被转义序列打断。全局关装饰,就是上面 YAML 里那行 command_decoration: false(默认 true);单条测试想临时关,isDecorated(false) 即可:
public function testWithoutDecoration(): void { $this->isDecorated(false); $tester = $this->runCommand('app:my-command'); self::assertStringNotContainsString("\033[", $tester->getDisplay()); }CI 环境建议全局关,省得每个测试各自处理一遍。
排雷清单:四条真实易错点
按踩坑频率排,上 CI 前逐条对照:
- 级别拼错会抛 OutOfBoundsException:setVerbosityLevel('foobar') 这种拼写在 getVerbosityLevel() 校验时直接炸,项目里的 testRunCommandVerbosityOutOfBound 就是验这个行为的,改配置先核对拼写。
- 只断输出不断退出码:命令失败但输出相似时测试照绿,getStatusCode() 断言缺一不可。
- CI 忘记 command_decoration: false:日志被 ANSI 字符污染,翻日志找问题先花十分钟。
- 同一测试多次 runCommand() 不复用内核:第三个参数传 true 复用,省掉每条命令重启内核的开销。
四件事收尾,源码入口在这
runCommand() 管执行与捕获,verbosity 两级配置管输出详略,setInputs() 与 isDecorated() 各管交互和乱码,退出码断言兜底——覆盖绝大多数 Symfony Command 测试。想深挖去两处:src/Test/WebTestCase.php 是全部能力的实现入口,tests/Command/CommandTest.php 里有各详细级别与交互输入的完整断言样例。老规矩:查源码比翻文档快。
【免费下载链接】nuclei-templatesCommunity curated list of templates for the nuclei engine to find security vulnerabilities.项目地址: https://gitcode.com/GitHub_Trending/nu/nuclei-templates
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考