如何在Laravel 5.4中使用ask()测试工匠命令

Lin*_* Lg 5 phpunit laravel mockery laravel-5.4

尝试使用ask()函数为laravel php artisan命令编写测试.我之前从未使用过嘲弄,但是当我尝试运行测试时,它会冻结,所以我猜,我做错了什么.

MyCommand.php:

public function handle()
    {
        $input['answer1'] = $this->ask('Ask question 1');
        $input['answer2'] = $this->ask('Ask question 2');
        $input['answer3'] = $this->ask('Ask question 3');


        //--- processing validation        
        $validator = Validator::make($input, [
            'answer1' => 'required',
            'answer2' => 'required',
            'answer3' => 'required',

        ]);

        if ($validator->fails()) {
            // processing error
            }
        } else {
            // saving to DB
        }
    }
Run Code Online (Sandbox Code Playgroud)

我的单元测试:

    $command = m::mock('\App\Console\Commands\Questions');


            $command->shouldReceive('ask')              
                  ->andReturn('Answer 1')
                  ->shouldReceive('ask')
                  ->andReturn('Answer 2')
                  ->shouldReceive('ask')
                  ->andReturn('Answer 3')


            $this->artisan('myCommand:toRun');

$this->assertDatabaseHas('myTable', [
            'question1' => 'answer1'
        ]);
Run Code Online (Sandbox Code Playgroud)

//

100*_*les 0

拉拉维尔 5.4 - 5.6

这里的实际问题是运行控制台命令正在等待用户输入,但是我们是通过 PHPUnit 运行它,因此我们无法输入任何内容。

遇到单元测试的限制一开始可能会令人沮丧,但是您发现的限制最终可能会因祸得福。

目前,您的实现与视图紧密耦合(控制台命令,因此对于管理员来说是一个视图,但仍然是一个视图。)这里可以做的是将任何逻辑放在一个可以利用的单独的类中MyCommand,并且 PHPUnit 可以实际自行测试。我们知道运行自定义命令的基本原理是有效的,如 Laravel 单元测试所示,因此我们可以将逻辑卸载到单独的可测试类中。

你的新类可能看起来像这样:

class CommandLogic
{

    public function getQuestion1Text()
    {
        return 'Ask question 1';
    }

    public function getQuestion2Text()
    {
        return 'Ask question 2';
    }

    public function getQuestion3Text()
    {
        return 'Ask question 3';
    }

    public function submit(array $input)
    {
        $validator = \Illuminate\Support\Facades\Validator::make($input, [
            'answer1' => 'required',
            'answer2' => 'required',
            'answer3' => 'required',
        ]);

        if ($validator->fails()) {
            // processing error
        } else {
            // saving to DB
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

...您的实际单元测试,如下所示:

$commandLogic = new CommandLogic();
$sampleInput = [
    'answer1' => 'test1',
    'answer2' => 'test2',
    'answer3' => 'test3',
];

$commandLogic->submit($sampleInput);
$this->assertDatabaseHas('myTable', [
    'question1' => 'test1'
]);
Run Code Online (Sandbox Code Playgroud)

...以及你的控制台命令,如下所示:

public function handle()
{
    $commandLogic = new CommandLogic();
    $input['answer1'] = $this->ask($commandLogic->getQuestion1Text());
    $input['answer2'] = $this->ask($commandLogic->getQuestion2Text());
    $input['answer3'] = $this->ask($commandLogic->getQuestion3Text());

    $commandLogic->submit($input);
}
Run Code Online (Sandbox Code Playgroud)

这强制执行单一职责原则,并将代码库中的移动部分分开。我知道这可能感觉有点逃避,但在 Laravel 5.4 中测试这些东西是很困难的。如果您愿意升级到 5.7 或更高版本,请阅读以下内容...


拉拉维尔 5.7+

Laravel 5.7 引入了运行控制台测试的能力,这满足了这个问题所要求的确切要求 - https://laravel.com/docs/5.7/console-tests。这更多的是完整的集成测试而不是单元测试。