laravel - 如何在 Laravel 5.4 中使用 ask() 测试 Artisan 命令

标签 laravel laravel-5 phpunit mockery

尝试使用 ask() 函数为 laravel php artisan 命令编写测试。我以前从未使用过 mock ,但是当我尝试运行测试时,它会卡住,所以我想,我做错了什么。
我的命令.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
        }
    }
我的单元测试:
    $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'
    ]);

最佳答案

Laravel 5.4 - 5.6

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

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

目前,您的实现与 View 紧密耦合(控制台命令,因此是管理员的 View ,但仍然是 View 。)这里可以做的是将任何逻辑放在一个单独的类中,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
        }
    }

}

...您的实际单元测试,如下所示:
$commandLogic = new CommandLogic();
$sampleInput = [
    'answer1' => 'test1',
    'answer2' => 'test2',
    'answer3' => 'test3',
];

$commandLogic->submit($sampleInput);
$this->assertDatabaseHas('myTable', [
    'question1' => 'test1'
]);

...和您的控制台命令,如下所示:
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);
}

这会强制执行 single responsibility principle并将代码库中的移动部分分开。我知道这可能有点像警察,但在 Laravel 5.4 中测试这些东西很困难。如果您愿意升级到 5.7 或更高版本,请阅读以下内容...

Laravel 5.7+

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

关于laravel - 如何在 Laravel 5.4 中使用 ask() 测试 Artisan 命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50254550/

相关文章:

javascript - 创建一个函数来编辑和删除表格中的输入 - Laravel 5.2

PHPUnit单元测试: Handling session_start() in a method

php - 为什么使用 Laravel 在一个文件中有多个测试方法会引发错误?

php - 加快laravel查询速度[解决]

php - Laravel 5 在数组中添加元素不起作用

laravel-5 - Vue js;Vue路由器不是简单路由中的构造函数错误

symfony - Phunit错误: You cannot create the client used in functional tests if the BrowserKit component is not available

php - Laravel App 执行两个请求,但第二个不需要

laravel - 未设置/存储 Httponly cookie (Laravel/Vue)

php - laravel 中的 Jwt-Auth 可以处理多服务器配置中的无效 token 吗?