Laravel 5.4中如何测试含ask()方法的Artisan命令
解决Laravel Artisan命令
ask()方法Mock测试卡顿问题 看起来你遇到的核心问题是手动创建的Mock实例没被Artisan工具使用,再加上Mockery的调用设置有误,导致测试时实际跑了真实的命令,卡在等待用户输入的环节。我帮你一步步修正:
1. 先修正Mockery的ask()模拟逻辑
你原来的链式写法有问题,连续调用shouldReceive('ask')会覆盖之前的设置。得针对每个提问(或者按调用顺序)指定返回值,两种写法都可以:
方式一:匹配具体提问内容(更严谨)
$command = Mockery::mock('\App\Console\Commands\Questions'); // 针对每个问题分别设置返回值 $command->shouldReceive('ask') ->with('Ask question 1') ->andReturn('Answer 1') ->shouldReceive('ask') ->with('Ask question 2') ->andReturn('Answer 2') ->shouldReceive('ask') ->with('Ask question 3') ->andReturn('Answer 3');
方式二:按调用次数批量返回(更简洁)
如果不需要匹配具体提问文本,只需要按顺序返回答案:
$command->shouldReceive('ask') ->times(3) // 指定调用3次 ->andReturn('Answer 1', 'Answer 2', 'Answer 3'); // 按顺序返回对应值
2. 让Artisan使用你的Mock实例
光创建Mock没用,得把它绑定到Laravel的容器里,这样$this->artisan()调用时才会用你的Mock,而不是实例化真实的命令类:
$this->app->instance(\App\Console\Commands\Questions::class, $command);
完整的测试代码示例
public function testCommandSavesToDatabase() { // 创建命令的Mock实例 $command = Mockery::mock('\App\Console\Commands\Questions'); // 模拟三次ask调用的返回值 $command->shouldReceive('ask') ->with('Ask question 1') ->andReturn('Answer 1') ->shouldReceive('ask') ->with('Ask question 2') ->andReturn('Answer 2') ->shouldReceive('ask') ->with('Ask question 3') ->andReturn('Answer 3'); // 将Mock绑定到容器,替换真实的命令类 $this->app->instance(\App\Console\Commands\Questions::class, $command); // 运行Artisan命令 $this->artisan('myCommand:toRun'); // 验证数据库是否正确保存数据 $this->assertDatabaseHas('myTable', [ 'question1' => 'Answer 1', // 注意这里要和你实际保存的字段值对应,原代码里的'answer1'是变量名,不是值 'question2' => 'Answer 2', 'question3' => 'Answer 3', ]); }
额外注意事项
- 确保你的命令类的
$signature属性确实是myCommand:toRun,否则$this->artisan()找不到对应的命令。 - 测试类记得在
tearDown()方法里加上Mockery::close();,避免Mockery残留影响其他测试。 - 原测试里的
assertDatabaseHas参数要和你实际存入数据库的字段、值对应,别把变量名(比如answer1)当成字段值用。
内容的提问来源于stack exchange,提问作者Linas Lg
相关产品推荐
相关产品推荐

