如何测试Laravel Artisan命令的输出和交互? (expectsQuestion/assertExitCode)

Laravel测试Artisan命令需用expectsQuestion预设交互输入,严格匹配提示字符串(含空格标点),并按顺序链式调用;输出断言用getDisplay()获取带ANSI码的原始内容,配合strip_tags()或正则清理后验证;assertExitCode(0)失效常因未捕获异常、手动exit或构造函数报错导致命令未执行到结尾。

如何测试laravel artisan命令的输出和交互? (expectsquestion/assertexitcode)

如何用 expectsQuestion 模拟用户输入

Artisan 命令里用了 $this->ask()$this->confirm() 等交互方法时,直接跑测试会卡住。Laravel 提供了 expectsQuestion 来预设回答,但要注意它只匹配「完全一致的提示字符串」——包括空格和标点。

  • expectsQuestion 必须在 artisan() 调用前链式调用,顺序错就无效
  • 如果命令里用了 $this->ask('Name? ', 'default'),测试中必须写 expectsQuestion('Name? ', 'alice'),末尾空格不能少
  • $this->confirm('Continue?'),传 truefalse 即可,但字符串提示仍要一字不差
  • 多个交互按出现顺序依次调用 expectsQuestion,不能跳过中间某一个
public function test_it_prompts_for_name_and_email()
{
    $this->artisan('make:user')
        ->expectsQuestion('Name? ', 'Taylor')
        ->expectsQuestion('Email? ', 'taylor@laravel.com')
        ->assertExitCode(0);
}

如何捕获并断言命令输出内容

光看退出码不够,常需验证是否打印了预期文本。Laravel 的 artisan() 测试方法默认不返回输出,得用 run() + getDisplay() 手动抓取。

  • 不要用 assertSee(),那是 HTTP 测试用的;Artisan 命令测试里得靠 getDisplay()
  • getDisplay() 返回带 ANSI 转义符的原始输出,含颜色控制符(如 /x1B[32m),断言前建议用 strip_tags() 或正则清理
  • 若命令输出含动态值(如时间戳、UUID),改用 assertStringContainsString() 或正则匹配关键静态部分
  • 错误输出走 getErrorOutput(),比如 php artisan invalid:command 的报错信息
$output = $this->artisan('list')->run();
$this->assertStringContainsString('make:user', $output->getDisplay());

为什么 assertExitCode(0) 有时不生效

assertExitCode() 看似简单,但实际失败往往不是逻辑错,而是命令提前异常终止或没真正执行到结尾。

造好物

造好物

一站式AI造物设计平台

下载

  • 命令里抛出未捕获异常(如数据库连接失败)会导致退出码为 1,但测试可能因异常中断而根本没走到 assertExitCode
  • 用了 exit()die() —— Artisan 命令严禁手动 exit,应改用 return self::FAILURE
  • handle() 外部(比如构造函数)抛异常,命令甚至不会进入执行流程,assertExitCode 不会被触发
  • 测试中调用的是命令实例而非 shell 进程,所以 exec('php artisan ...') 这种绕过框架的方式会让所有内置断言失效

交互+输出+退出码要一起测才真实

单测某个环节容易漏掉组合问题。比如用户输错格式后命令打印错误提示并退出 1,这种场景必须三者联动验证。

  • 先用 expectsQuestion 给非法输入(如邮箱不带 @)
  • 再用 getDisplay() 确认错误文案出现
  • 最后用 assertExitCode(1) 确保没静默成功
  • 注意:如果命令内部用 $this->error() 输出,它也出现在 getDisplay() 里,不是 getErrorOutput()

最易忽略的是 ANSI 颜色字符干扰断言,以及提示字符串里隐藏的不可见空格 —— 这类细节不打日志根本看不出哪里不匹配。

https://www.php.cn/faq/1982589.html

发表回复

Your email address will not be published. Required fields are marked *