【问题标题】:Laravel 5 console (artisan) command unit testsLaravel 5 控制台(工匠)命令单元测试
【发布时间】:2020-06-24 23:11:08
【问题描述】:

我正在将我的 Laravel 4.2 应用程序迁移到 5.1(从 5.0 开始),并且我的控制台命令单元测试遇到了很多麻烦。我有工匠命令,我需要测试生成的控制台输出、正确的问题/响应处理以及与其他服务的交互(使用模拟)。遗憾的是,Laravel 文档在测试控制台命令方面保持沉默。

我终于找到了一种创建这些测试的方法,但感觉就像是对那些 setLaravelsetApplication 调用进行了破解。

有没有更好的方法来做到这一点?我希望我可以将我的模拟实例添加到 Laravel IoC 容器中,并让它创建命令来测试所有正确设置的内容。恐怕我的单元测试很容易被较新的 Laravel 版本破坏。

这是我的单元测试:

使用语句:

use Mockery as m;
use App\Console\Commands\AddClientCommand;
use Symfony\Component\Console\Tester\CommandTester;

设置

public function setUp() {
    parent::setUp();

    $this->store = m::mock('App\Services\Store');

    $this->command = new AddClientCommand($this->store);

    // Taken from laravel/framework artisan command unit tests
    // (e.g. tests/Database/DatabaseMigrationRollbackCommandTest.php)
    $this->command->setLaravel($this->app->make('Illuminate\Contracts\Foundation\Application'));

    // Required to provide input to command questions (provides command->getHelper())
    // Taken from ??? when I first built my command tests in Laravel 4.2
    $this->command->setApplication($this->app->make('Symfony\Component\Console\Application'));
}

作为命令参数提供的输入。检查控制台输出

public function testReadCommandOutput() {
    $commandTester = new CommandTester($this->command);

    $result = $commandTester->execute([
        '--client-name' => 'New Client',
    ]);

    $this->assertSame(0, $result);
    $templatePath = $this->testTemplate;

    // Check console output
    $this->assertEquals(1, preg_match('/^Client \'New Client\' was added./m', $commandTester->getDisplay()));
}

模拟键盘按键提供的输入

public function testAnswerQuestions() {
    $commandTester = new CommandTester($this->command);

    // Simulate keyboard input in console for new client
    $inputs = $this->command->getHelper('question');
    $inputs->setInputStream($this->getInputStream("New Client\n"));
    $result = $commandTester->execute([]);

    $this->assertSame(0, $result);
    $templatePath = $this->testTemplate;

    // Check console output
    $this->assertEquals(1, preg_match('/^Client \'New Client\' was added./m', $commandTester->getDisplay()));
}

protected function getInputStream($input) {
    $stream = fopen('php://memory', 'r+', false);
    fputs($stream, $input);
    rewind($stream);
    return $stream;
}

更新

  1. 这在 Laravel 5.1 中不起作用#11946

【问题讨论】:

  • 不幸的是,我不得不注释掉涉及动态输入的测试。 Laravel 的人似乎没有根据对问题的响应将正确测试命令视为优先事项:“我们对 PR 持开放态度。:) 5.1 已因此类更改而关闭。”

标签: php unit-testing laravel laravel-5 laravel-5.1


【解决方案1】:

我之前已经这样做了 - 我的控制台命令返回一个 json 响应:

public function getConsoleResponse()
{
    $kernel = $this->app->make(Illuminate\Contracts\Console\Kernel::class);
    $status = $kernel->handle(
        $input = new Symfony\Component\Console\Input\ArrayInput([
            'command' => 'test:command', // put your command name here
        ]),
        $output = new Symfony\Component\Console\Output\BufferedOutput
    );

    return json_decode($output->fetch(), true);
}

所以,如果你想把它放在它自己的命令测试器类中,或者作为 TestCase 等中的一个函数......由你决定。

【讨论】:

  • 看起来比我的解决方案好多了!看起来你也有依赖注入工作。我目前没有使用 Laravel,因此无法对其进行测试。
  • 花了我好几个小时来解决这个问题。但它是我现在保存在 Gist 中的那些 sn-ps 之一!
  • 我只能得到“null”作为这个的回报
【解决方案2】:
use Illuminate\Support\Facades\Artisan;
use Symfony\Component\Console\Output\BufferedOutput;

$output = new BufferedOutput();

Artisan::call('passport:client', [
    '--password' => true,
    '--name' => 'Temp Client',
    '--no-interaction' => true,
], $output);

$stringOutput = $output->fetch();


【讨论】:

  • 不错。这个对我有用,接受的答案没有。
猜你喜欢
  • 2018-02-21
  • 2016-10-05
  • 1970-01-01
  • 2017-12-24
  • 2015-04-13
  • 2014-08-30
  • 2016-11-28
  • 2014-09-07
  • 2013-05-30
相关资源
最近更新 更多