【问题标题】:How To Test Artisan Commands with ask() in Laravel 5.4如何在 Laravel 5.4 中使用 ask() 测试 Artisan 命令
【发布时间】:2018-10-19 15:23:33
【问题描述】:

尝试使用 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
        }
    }

还有我的单元测试:

    $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 laravel-5 phpunit mockery


    【解决方案1】:

    Laravel 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
            }
        }
    
    }
    

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

    $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。这更像是一个完整的集成测试,而不是一个单元测试。

    【讨论】:

      猜你喜欢
      • 2023-04-02
      • 2014-03-21
      • 2017-10-10
      • 2019-11-13
      • 1970-01-01
      • 2016-05-20
      • 2015-11-14
      • 2015-02-21
      • 1970-01-01
      相关资源
      最近更新 更多