为什么静态方法难以进行测试?

16
为什么静态方法是难以测试的?如果可以,请用 PHP 举例说明。
3个回答

15

静态方法本身并不是无法测试的,但如果被测试的对象调用了一个静态方法,那么测试就无法"介入"并使其调用存根方法。如果被测试的对象调用的是一个普通方法,那么测试可以提供一个具有该方法存根实现的替代对象。

一般情况下,刚性依赖关系更难测试,而依赖注入(搜索谷歌)使代码更易于测试。

例如,假设我们有一个静态方法getCurrentUser(),被正在测试的类使用,如下所示:

class PostModel {
    //...
    public function getRecentPosts() {
        return $this->database->from('posts')
                ->where(array('user' => UserModel::getCurrentUser()))
                ->limit(10);
    }
}

现在UserModel::getCurrentUser()不能被替换成一个存根方法。如果我们将其变为通过对象引用调用的常规方法,我们就可以在测试中传入一个替代的存根对象。

class PostModel {
    private $userModel;
    public function __construct($userModel) { 
        $this->userModel = $userModel;
    }
    //...
    public function getRecentPosts() {
        return $this->database->from('posts')
                ->where(array('user' => $this->userModel->getCurrentUser()))
                ->limit(10);
    }
}

能否举个例子来说明这个问题? - Czar Pino
为什么不呢? 我不明白你的意思。如果你在依赖注入方面有问题,我认为你应该将用户对象传递给getRecentPosts而不是整个类,并且我认为你无法轻松地测试PostModel,因为你的模式是错误的。 测试静态方法没有问题。 如果我有错误,请指出来。 - Aminkt
是的,将依赖项作为函数参数获取也可以。 - mpartel

4
静态方法是可测试的:http://sebastian-bergmann.de/archives/883-Stubbing-and-Mocking-Static-Methods.html(这是PHP),但如果你想要测试类之间的交互(例如使用模拟和伪造对象),则可能不希望使用它。尽管如此,phpunit 3.5允许您对其进行存根。
您还可以查看何时在PHP中使用静态变量/函数?或搜索有关何时使用静态方法的信息。
我在类内部使用静态方法(即标记为private或protected),因为它们在我使用的语言中更快。

1
是的,PHPUnit 显然现在支持静态方法的单元测试。但 Sebastian Berghman 将其称为无法测试代码的一种解决方法。 - Czar Pino

3

良好定义的静态方法是完全可测试的。你看,问题不在于方法本身,而在于方法的依赖关系。如果该方法及其依赖项(以及依赖项的依赖项)是idempotent,那么就没有问题。问题出现在你的静态方法调用其他方法时,例如依赖于全局变量的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接