2012-01-22 157 views
4

作为学习Symfony2的一部分,我试图编写一个非常简单的控制台命令,该命令仅运行phpcs(PHP代码嗅探器)。无法测试Symfony2控制台命令

这里的执行功能,该功能在扩展ContainerAwareCommand类:

protected function execute(InputInterface $input, OutputInterface $output) 
{ 
    $output->writeln('<info>Generating PHP Code Sniffer report...</info>'); 
    exec('phpcs ./src > ./app/logs/phpcs.log'); 

    if ($input->getOption('noprompt') == null) { 
     $dialog = $this->getHelperSet()->get('dialog'); 
     if ($dialog->askConfirmation($output, '<question>Open report in TextMate? (y/n)?</question>', false)) { 
      exec('mate ./app/logs/phpcs.log'); 
     } 
    } 

    $output->writeln('<info>...done</info>'); 
} 

我能够通过运行

app/console mynamespace:ci:phpcs 

执行控制台命令和它完美的作品。输出文件按预期生成。

我试图测试myNameSpace对象:使用下面的函数(这是一个化PHPUnit_Framework_TestCase的一部分)phpcs命令::CI

public function testExecute() 
{ 
    $kernel = new \AppKernel("test", true); 
    $kernel->boot(); 

    $application = new Application($kernel); 
    $application->add(new PhpCodeSnifferCommand()); 

    $command = $application->find('mynamespace:ci:phpcs'); 
    $commandTester = new CommandTester($command); 
    $commandTester->execute(array('command' => $command->getName())); 

    // ... Test if output file was created here ... ommitted for brevity ... // 
} 

然而,试图通过该单元测试来执行它时,它以下输出失败:

sh: phpcs: command not found 

有没有人有一个想法,为什么发生这种情况?

PS:我观察到的一件事是,当我在命令行中注释掉'exec'命令行时,测试运行(不通过,但不会呻吟phpcs不存在),所以问题肯定与执行命令。

PHPUnit测试是否以不同的用户身份运行,其中phpcs不可用?

+0

你是如何运行PHPUnit的:作为你自己的控制台,Jenkins内部还是其他一些CI工具,从IDE? Jenkins在我的Ubuntu系统上以'jenkins'用户身份运行,但我的IDE像控制台一样运行。 –

+0

我通常从IntelliJ运行它们,但也尝试从命令行运行。 –

+0

确保'phpcs'已经安装在每个人的'$ PATH'上,而不仅仅是你自己的。这是典型的情况,所以这有点奇怪。嘲笑确实解决了它,但可能只是推迟了下游的问题。 –

回答

5

对于单元测试,您应该考虑嘲笑exec()的调用。这将加快您的测试并避免这样的环境问题。对于这种情况,您可以简单地添加方法,将exec()称为您可以模拟测试的课程。

class PhpCodeSnifferCommand extends ... 
{ 
    protected function execute(InputInterface $input, OutputInterface $output) 
    { 
     // ... 
     runReport(); 
     // ... 
       viewReport(); 
     // ... 
    } 

    protected function runReport() { 
     exec('phpcs ./src > ./app/logs/phpcs.log'); 
    } 

    protected function viewReport() { 
     exec('mate ./app/logs/phpcs.log'); 
    } 
} 

嘲讽可以更容易地确认三种可能的路径:

  1. 该命令告诉不提示用户查看报告。
  2. 该命令被告知提示;用户说不。
  3. 该命令被告知提示;用户说是的。

将每个路径放在自己的测试中。您可以将通用代码放入测试帮助程序中,以缩短测试时间。

public function testRunsReportWithoutAskingToView() 
{ 
    // ... 

    $application = new Application($kernel); 
    $phpcs = $this->getMock('PhpCodeSnifferCommand', array('runReport', 'viewReport')); 
    $phpcs->expects($this->once())->method('runReport'); 
    $phpcs->expects($this->never())->method('viewReport'); 
    $application->add($phpcs); 

    // Tell the command not to prompt to view the report ... 
} 

public function testRunsAndViewsReport() 
{ 
    // ... 

    $application = new Application($kernel); 
    $phpcs = $this->getMock('PhpCodeSnifferCommand', array('runReport', 'viewReport')); 
    $phpcs->expects($this->once())->method('runReport'); 
    $phpcs->expects($this->once())->method('viewReport'); 
    $application->add($phpcs); 

    // Tell the command to prompt to view and the dialog to hit "Y" for you ... 
} 

public function testRunsReportButDoesntViewIt() 
{ 
    // ... 

    $application = new Application($kernel); 
    $phpcs = $this->getMock('PhpCodeSnifferCommand', array('runReport', 'viewReport')); 
    $phpcs->expects($this->once())->method('runReport'); 
    $phpcs->expects($this->never())->method('viewReport'); 
    $application->add($phpcs); 

    // Tell the command to prompt to view and the dialog to hit "N" for you ... 
} 
+0

感谢您的回答,这绝对是解决问题的最佳方式。我不知道为什么我不考虑嘲笑对exec的呼吁。出色的建议! –