我正在尝试规范Symfony命令,我想用SymfonyStyle格式化输出
<?php
namespace AcmeAppBundleCommand;
use SymfonyBundleFrameworkBundleCommandContainerAwareCommand;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
use SymfonyComponentConsoleStyleSymfonyStyle;
class SomeCommand extends ContainerAwareCommand
{
//....
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$io->title('Feed import initiated');
}
}
和规范文件:
<?php
namespace specAcmeAppBundleCommand;
use PhpSpecObjectBehavior;
use ProphecyArgument;
use SymfonyBundleFrameworkBundleCommandContainerAwareCommand;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputBufferedOutput;
use SymfonyComponentConsoleOutputOutputInterface;
use SymfonyComponentDependencyInjectionContainerInterface;
class SomeCommandSpec extends ObjectBehavior
{
//...
function it_fetches_social_feeds(
ContainerInterface $container,
InputInterface $input,
OutputInterface $output,
SymfonyStyle $symfonyStyle
) {
// With options
$input->bind(Argument::any())->shouldBeCalled();
$input->hasArgument('command')->shouldBeCalled();
$input->isInteractive()->shouldBeCalled();
$input->validate()->shouldBeCalled();
$symfonyStyle->title(Argument::any())->shouldBeCalled();
$this->setContainer($container);
$this->run($input, $output);
}
}
但是我收到此错误:
exception [err:Error("__clone method called on non-object")] has been thrown.
0 vendor/symfony/symfony/src/Symfony/Component/Console/Style/SymfonyStyle.php:50
throw new PhpSpecExceptionErrorException("__clone method called on ...")
1 vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:866
SymfonyComponentConsoleCommandCommand->run([obj:SymfonyComponentConsoleInputArgvInput], [obj:SymfonyComponentConsoleOutputConsoleOutput])
2 vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:193
SymfonyComponentConsoleApplication->doRunCommand([obj:PhpSpecConsoleCommandRunCommand], [obj:SymfonyComponentConsoleInputArgvInput], [obj:SymfonyComponentConsoleOutputConsoleOutput])
3 vendor/phpspec/phpspec/src/PhpSpec/Console/Application.php:102
SymfonyComponentConsoleApplication->doRun([obj:SymfonyComponentConsoleInputArgvInput], [obj:SymfonyComponentConsoleOutputConsoleOutput])
4 vendor/phpspec/phpspec/bin/phpspec:26
SymfonyComponentConsoleApplication->run()
5 vendor/phpspec/phpspec/bin/phpspec:28
{closure}("3.2.2")
在SymfonyStyle的第50行是:
public function __construct(InputInterface $input, OutputInterface $output)
{
$this->input = $input;
/* line 50 */ $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter());
// Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.
$this->lineLength = min($this->getTerminalWidth() - (int) (DIRECTORY_SEPARATOR === '\'), self::MAX_LINE_LENGTH);
parent::__construct($output);
}
phpspec
抱怨clone $output->getFormatter()
是我做错了什么,还是错过了什么?
更新
这是我let
方法:
function let(SymfonyStyle $symfonyStyle, InputInterface $input, OutputInterface $output)
{
$symfonyStyle->beConstructedWith([$input->getWrappedObject(), $output->getWrappedObject()]);
}
你错过了这个
function it_fetches_social_feeds(
ContainerInterface $container,
InputInterface $input,
OutputInterface $output,
SymfonyStyle $symfonyStyle
) {
// .... other code
$prophet = new Prophet();
$formatter = $prophet->prophesize(OutputFormatterInterface::class);
$output->getFormatter()->willReturn($formatter);
// .... more code
}
您可以将其放置在所需的位置,但在呼叫完成之前。
通过这种方式,您创建了一个基本上是有行为和没有期望的Double
Stub
。您可以将其视为一个"代理",它将拦截方法调用并返回您"教"它返回的内容。
在你的例子中,事情被破坏了,因为你的双OutputInterface
会返回null
因为它不是一个"真实"的对象。
如果您需要执行不同类型的规范,我还建议存根getVerbosity
行为。
顺便说一句,您可以在phpspec指南和预言指南中阅读有关双打的更多信息
看一个例子,SymfonyStyle似乎从未在规范类中传递过。
命令的 execute 函数也不会传递它,只会传递输入和输出类(它作为局部变量创建的样式类)。