zenstruck / console-test
用于测试 Symfony 控制台命令的替代方案,具有个人观点的辅助工具。
v1.6.0
2024-07-24 14:03 UTC
Requires
- php: >=8.0
- symfony/console: ^5.4|^6.0|^7.0
- zenstruck/assert: ^1.0
Requires (Dev)
- phpstan/phpstan: ^1.4
- phpunit/phpunit: ^9.5.0
- symfony/framework-bundle: ^5.4|^6.0|^7.0
- symfony/phpunit-bridge: ^6.2|^7.0
README
用于测试 Symfony 控制台命令的替代方案,具有个人观点的辅助工具。此包是 Symfony\Component\Console\Tester\CommandTester
的替代品,可以帮助使您的测试更加表达性和简洁。
安装
composer require --dev zenstruck/console-test
Symfony 框架使用
您可以通过在您的 KernelTestCase
/WebTestCase
测试中使用 InteractsWithConsole
特性来运行测试中的控制台命令。
use App\Command\CreateUserCommand; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Zenstruck\Console\Test\InteractsWithConsole; class CreateUserCommandTest extends KernelTestCase { use InteractsWithConsole; public function test_can_create_user(): void { $this->executeConsoleCommand('create:user kbond --admin --role=ROLE_EMPLOYEE --role=ROLE_MANAGER') ->assertSuccessful() // command exit code is 0 ->assertOutputContains('Creating admin user "kbond"') ->assertOutputContains('with roles: ROLE_EMPLOYEE, ROLE_MANAGER') ->assertOutputNotContains('regular user') ; // advanced usage $this->consoleCommand(CreateUserCommand::class) // can use the command class or "name" ->splitOutputStreams() // by default stdout/stderr are combined, this options splits them ->addArgument('kbond') ->addOption('--admin') // with or without "--" prefix ->addOption('role', ['ROLE_EMPLOYEE', 'ROLE_MANAGER']) ->addOption('-R') // shortcut options require the "-" prefix ->addOption('-vv') // by default, output has normal verbosity, use the standard options to change (-q, -v, -vv, -vvv) ->addOption('--ansi') // by default, output is undecorated, use this option to decorate ->execute() // run the command ->assertSuccessful() ->assertStatusCode(0) // equivalent to ->assertSuccessful() ->assertOutputContains('Creating admin user "kbond"') ->assertErrorOutputContains('this is in stderr') // used in conjunction with ->splitOutputStreams() ->assertErrorOutputNotContains('admin user') // used in conjunction with ->splitOutputStreams() ->dump() // dump() the status code/outputs and continue ->dd() // dd() the status code/outputs ; // testing interactive commands $this->executeConsoleCommand('create:user', ['kbond']) ->assertSuccessful() ->assertOutputContains('Creating regular user "kbond"') ; // advanced testing interactive commands $this->consoleCommand(CreateUserCommand::class) ->addInput('kbond') ->addOption('--no-interaction') // commands are run interactively if input is provided, use this option to disable ->execute() ->assertSuccessful() ->assertOutputContains('Creating regular user "kbond"') ; // test command throws exception $this->consoleCommand(CreateUserCommand::class) ->expectException(\RuntimeException::class, 'Username required!') ->assertStatusCode(1) // equivalent to ->assertFaulty() ->assertOutputContains('Could not create user!') // can still make assertions on output before exception was thrown ; // test completion $this->consoleCommand('create:user') ->complete('') ->is(['kevin', 'john', 'jane']) ->contains('kevin') // chain assertions ->back() // fluently go back to the TestCommand ->complete('kevin --role=')->is(['ROLE_EMPLOYEE', 'ROLE_MANAGER']) ; // access result $result = $this->executeConsoleCommand('create:user'); $result->statusCode(); $result->output(); $result->errorOutput(); } }
独立使用
您可以在单元测试或非 Symfony 框架环境中测试命令。
use App\Command\CreateUserCommand; use PHPUnit\Framework\TestCase; use Zenstruck\Console\Test\TestCommand; class CreateUserCommandTest extends TestCase { public function test_can_create_user(): void { TestCommand::for(new CreateUserCommand(/** args... */)) ->execute('kbond --admin --role=ROLE_EMPLOYEE --role=ROLE_MANAGER') ->assertSuccessful() // command exit code is 0 ->assertOutputContains('Creating admin user "kbond"') ->assertOutputContains('with roles: ROLE_EMPLOYEE, ROLE_MANAGER') ->assertOutputNotContains('regular user') ; // advanced usage TestCommand::for(new CreateUserCommand(/** args... */)) ->splitOutputStreams() // by default stdout/stderr are combined, this options splits them ->addArgument('kbond') ->addOption('--admin') // with or without "--" prefix ->addOption('role', ['ROLE_EMPLOYEE', 'ROLE_MANAGER']) ->addOption('-R') // shortcut options require the "-" prefix ->addOption('-vv') // by default, output has normal verbosity, use the standard options to change (-q, -v, -vv, -vvv) ->addOption('--ansi') // by default, output is undecorated, use this option to decorate ->execute() ->assertSuccessful() ->assertStatusCode(0) // equivalent to ->assertSuccessful() ->assertOutputContains('Creating admin user "kbond"') ->assertErrorOutputContains('this is in stderr') // used in conjunction with ->splitOutputStreams() ->assertErrorOutputNotContains('admin user') // used in conjunction with ->splitOutputStreams() ->dump() // dump() the status code/outputs and continue ->dd() // dd() the status code/outputs ; // testing interactive commands TestCommand::for(new CreateUserCommand(/** args... */)) ->addInput('kbond') ->addOption('--no-interaction') // commands are run interactively if input is provided, use this option to disable ->execute() ->assertSuccessful() ->assertOutputContains('Creating regular user "kbond"') ; // test command throws exception TestCommand::for(new CreateUserCommand(/** args... */)) ->expectException(\RuntimeException::class, 'Username required!') ->assertStatusCode(1) ->assertOutputContains('Could not create user!') // can still make assertions on output before exception was thrown ; // test completion TestCommand::for(new CreateUserCommand(/** args... */)) ->complete('') ->is(['kevin', 'john', 'jane']) ->contains('kevin') // chain assertions ->back() // fluently go back to the TestCommand ->complete('kevin --role=')->is(['ROLE_EMPLOYEE', 'ROLE_MANAGER']) ; // access result $result = TestCommand::for(new CreateUserCommand(/** args... */))->execute(); $result->statusCode(); $result->output(); $result->errorOutput(); } }
标准化终端宽度
在不同的终端环境中(例如 Windows、Linux、Github Actions),默认的终端宽度可能不同。由于某些 Symfony 输出辅助工具使用此值来包装长行,这可能导致不同环境中的输出断言失败。建议通过为您的测试套件设置 COLUMNS
环境变量来标准化终端宽度。
<!-- phpunit.xml --> <phpunit> <!-- ... --> <php> <env name="COLUMNS" value="120" /> </php> <!-- ... --> </phpunit>