在指定使用 SymfonyStyle 进行样式化输出的 Symfony 命令时,获取在非对象上调用的克隆方法
Getting clone method called on non-object when specing Symfony command that uses SymfonyStyle for styled output
我正在尝试指定 Symfony 命令,我想使用 SymfonyStyle 格式化输出
<?php
namespace Acme\AppBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class SomeCommand extends ContainerAwareCommand
{
//....
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$io->title('Feed import initiated');
}
}
和规范文件:
<?php
namespace spec\Acme\AppBundle\Command;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
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 PhpSpec\Exception\ErrorException("__clone method called on ...")
1 vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:866
Symfony\Component\Console\Command\Command->run([obj:Symfony\Component\Console\Input\ArgvInput], [obj:Symfony\Component\Console\Output\ConsoleOutput])
2 vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:193
Symfony\Component\Console\Application->doRunCommand([obj:PhpSpec\Console\Command\RunCommand], [obj:Symfony\Component\Console\Input\ArgvInput], [obj:Symfony\Component\Console\Output\ConsoleOutput])
3 vendor/phpspec/phpspec/src/PhpSpec/Console/Application.php:102
Symfony\Component\Console\Application->doRun([obj:Symfony\Component\Console\Input\ArgvInput], [obj:Symfony\Component\Console\Output\ConsoleOutput])
4 vendor/phpspec/phpspec/bin/phpspec:26
Symfony\Component\Console\Application->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()]);
}
查看 example,SymfonyStyle 似乎从未在规范中通过 class。
命令的执行函数也不传递它,只是输入和输出classes(它作为局部变量创建的样式class)。
你错过了这个
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
}
你可以把它放在你想要的地方,但在通话结束之前。
通过这种方式,您创建了一个 Stub
,它基本上是一个 Double
,有行为但没有期望。您可以将其视为 "proxy",它将拦截方法调用并将您 "teach" 的内容 return 发送到 return。
在你的例子中,你的双 OutputInterface
会被破坏 return null
因为它不是 "real" 对象。
如果您需要执行不同类型的规格,我还建议存根 getVerbosity
行为。
顺便说一句,您可以在 phpspec guide and prophecy guide
中阅读有关双打的更多信息
我正在尝试指定 Symfony 命令,我想使用 SymfonyStyle 格式化输出
<?php
namespace Acme\AppBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class SomeCommand extends ContainerAwareCommand
{
//....
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$io->title('Feed import initiated');
}
}
和规范文件:
<?php
namespace spec\Acme\AppBundle\Command;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
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 PhpSpec\Exception\ErrorException("__clone method called on ...")
1 vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:866
Symfony\Component\Console\Command\Command->run([obj:Symfony\Component\Console\Input\ArgvInput], [obj:Symfony\Component\Console\Output\ConsoleOutput])
2 vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:193
Symfony\Component\Console\Application->doRunCommand([obj:PhpSpec\Console\Command\RunCommand], [obj:Symfony\Component\Console\Input\ArgvInput], [obj:Symfony\Component\Console\Output\ConsoleOutput])
3 vendor/phpspec/phpspec/src/PhpSpec/Console/Application.php:102
Symfony\Component\Console\Application->doRun([obj:Symfony\Component\Console\Input\ArgvInput], [obj:Symfony\Component\Console\Output\ConsoleOutput])
4 vendor/phpspec/phpspec/bin/phpspec:26
Symfony\Component\Console\Application->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()]);
}
查看 example,SymfonyStyle 似乎从未在规范中通过 class。
命令的执行函数也不传递它,只是输入和输出classes(它作为局部变量创建的样式class)。
你错过了这个
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
}
你可以把它放在你想要的地方,但在通话结束之前。
通过这种方式,您创建了一个 Stub
,它基本上是一个 Double
,有行为但没有期望。您可以将其视为 "proxy",它将拦截方法调用并将您 "teach" 的内容 return 发送到 return。
在你的例子中,你的双 OutputInterface
会被破坏 return null
因为它不是 "real" 对象。
如果您需要执行不同类型的规格,我还建议存根 getVerbosity
行为。
顺便说一句,您可以在 phpspec guide and prophecy guide
中阅读有关双打的更多信息