4

作为学习 Symfony2 的一部分,我正在尝试编写一个非常简单的控制台命令,它只运行 phpcs(PHP 代码嗅探器)。

这是扩展 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

它工作得很好。输出文件按预期生成。

我正在尝试使用以下函数(它是 PHPUnit_Framework_TestCase 的一部分)测试 mynamespace:ci:phpcs 命令:

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 不可用?

4

1 回答 1

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 ...
}
于 2012-01-22T20:34:47.380 回答