使用 Mockery 测试 Laravel Command 尝试

使用 Mockery 测试 Laravel Command 尝试

概述

由于 Laravel 官方支持的 Artisan 命令行测试原理为实际调用一次命令,再校验其输出。故如果仅测试 Command 类中的一个方法时就会无从下手。而 Command 的实例化也很复杂,源码看的头晕。关键的获取命令行输入始终无法模拟,所以想着能否借用 Mockery 工具模拟一个 Input 类,达到模拟输入的目的。

示例

现有 Command 代码如下。

<?php

...
use Illuminate\Console\Command;

class SampleCommand extends Command
{
    ...
    public function initMode()
    {
        return $this->option('init-mode');
    }
...

已知 \Illuminate\Console\Command::option($key) 方法是通过调用 \Symfony\Component\Console\Input\InputInterface::getOption($name) 实现的。

/**
 * Get the value of a command option.
 *
 * @param  string|null  $key
 * @return string|array|bool|null
 */
public function option($key = null)
{
    if (is_null($key)) {
        return $this->input->getOptions();
    }

    return $this->input->getOption($key);
}

\Illuminate\Console\Command::$input 属性可以通过 \Illuminate\Console\Command::setInput($input) 方法注入。

那么,可以通过 Mockery 模拟一个 \Symfony\Component\Console\Input\InputInterface 接口的实现,来替换原有的 $input

测试代码如下。

<?php

use Mockery;
use Tests\TestCase;

class SampleCommandTest extends TestCase
{
    public function testInitMode()
    {
        $command = $this->app->get(SampleCommand::class);
        $input = Mockery::mock(\Symfony\Component\Console\Input\InputInterface::class);
        $input->shouldReceive('getOption')->with('init-mode')->andReturn(false);
        $command->setInput($input);
        $this->assertFalse($commond->initMode());
    }
}

这样就能通过模拟一个 Input 来测试 Laravel Command 的一个获取输入选项值的方法了。

总结

虽然这个例子看起来没什么卵用,但是仔细思考一下的话,就能发现这套做法还是很有用的。

posted @ 2022-06-18 18:07  张little杰  阅读(124)  评论(0)    收藏  举报