如何对执行命令行程序的PHP类方法进行单元测试?

时间:2012-04-14 23:12:08

标签: php git unit-testing phpunit

对于我正在开发的PHP应用程序,我需要阅读当前的git修订版SHA,当然我可以通过使用shell_exec或反引号来轻松执行git命令行客户端。

我显然已将此调用放入其自己的方法中,因此我可以轻松地隔离并模拟其余的单元测试。所以我的班级看起来有点像这样:

class Task_Bundle
{

    public function execute()
    {
        // Do things
        $revision = $this->git_sha();
        // Do more things
    }

    protected function git_sha()
    {
        return `git rev-parse --short HEAD`;
    }
}

当然,虽然我可以通过模拟git_sha来测试大部分类,但我很难看到如何测试实际的git_sha()方法,因为我没有看到为它创建已知状态的方法。我认为单元测试中没有任何实际价值也会调用git rev-parse来比较结果?我想知道至少断言命令已经运行,但是我看不到任何方法来获取PHP执行的shell命令的历史 - 即使我指定PHP应该使用BASH而不是SH,历史列表会出现空,我认为因为单独的反引号执行是单独的终端会话。

我很想听听有关我如何测试此问题的任何建议,或者是否可以暂时保留该方法,并在将来维护应用时小心一点?

3 个答案:

答案 0 :(得分:5)

虽然你已经接受了答案,但是让我发布一些关于单元测试应该如何工作的东西,因为即使发布的解决方案确实有效并且确实很好,它也会有一些退款。

首先,您不希望实际执行命令,因为这会测试外部软件。从这一刻起,你依赖于你无法控制的外部东西(如果我想在我的电脑上测试你的软件会怎么样?我必须安装git或任何git-mock吗?)。你真正想要做的是查看命令行命令是否正确并且执行得好。

我之前一直在努力解决这个问题:我创建了一个执行shell_exec的类。我想要与shell进行交互,我注入了类并使用它。因此,对于测试,我可以模拟类,看看是否执行了正确的方法以及是否设置了正确的参数。

这有很多好处:

  • 我有一点与shell进行交互。如果将来发生任何变化,或者在执行命令之前我需要做任何事情,我可以将该行为添加到类中。 PHP函数很好地封装了。
  • 它适用于每台PC,即使shell_exec命令因任何原因无效。测试在每台PC(开发机器,测试服务器,集成服务器)上执行,无需担心外部依赖性。

当然,要验证您的软件是否作为一个整体运行,您必须进行不模拟任何内容的集成测试。但这是一个完全不同的情况。单元测试应该确保你的类(或方法)做它需要做的事情。有时这不是明确的,因为你可能决定在某个地方使用真正的类,因为嘲笑它会导致很多开销。但是,就我而言,如果它依赖于可能由于某些原因而无法安装或可能无法工作的外部库/软件,则它不再是任何单元测试。

答案 1 :(得分:1)

至少你可以做一些事情,比如检查退役的字符串以匹配/ ^ [abcdef 0-9] {7} $ /

答案 2 :(得分:0)

我想如果你真的想要,你可以写一个假的git并将它的位置添加到你的环境的PATH。让它做你需要做的任何验证,然后生成与真实事物一致的输出。如果你愿意的话,你甚至可以将它转发给真正的git,但是你无法保证结果。

你必须要小心,但是......你想做的就是这样,以至于这个班可以被误以为它真的是git,但如果你让它表现得太像了真实的是,这相当于写了你自己的半个版本的Git。