Laravel 5控制台(工匠)命令单元测试


Laravel 5 console (artisan) command unit tests

我正在将我的 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 中不起作用

我之前已经这样做了,如下所示 - 我的控制台命令返回一个 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等中的函数......取决于您。

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();