【问题标题】:Mock a function of an object created using a static method in PHP?模拟使用 PHP 中的静态方法创建的对象的函数?
【发布时间】:2012-03-23 20:12:26
【问题描述】:

我正在使用 ORM,我获取记录对象的方式是使用 FooModel::find(1)FooModel 有一个我需要模拟以进行测试的方法。我该怎么做? (不能使用 PHPUnit mock,因为这会给我一个模拟的 FooModel,它与 ID 为 1 的记录不对应。)

编辑

例子:

class FooModel
{
    // ORM model that fetches record from the DB

    public function thisNeedsToBeMocked()
    {
        // some code here that depends on external factors so should be part of unit tests
    }
}

我获取ID为1的记录的方式是:

$fooObject = FooModel::find(1);

在运行static 方法find() 后,我需要能够模拟$fooObjectthisNeedsToBeMocked()

【问题讨论】:

  • 你能试着解释一下你的问题吗?我有点困惑。
  • @Brad:我会编辑它。我担心它太短了。
  • @Brad:添加了更多细节。也许这有帮助?
  • @webbiedave:如果您阅读了这两个问题,我不认为这可能是重复的。另一个问题的 OP 想要模拟 static 方法。我想模拟使用 static 方法创建的对象的不同/单独/无关方法。

标签: php unit-testing phpunit


【解决方案1】:

您遇到了一个经典的单元测试问题。您用来静态调用的类名是全局命名空间的一部分。这意味着没有一点可以插入模拟。这不是你可以在这里做的魔法,要解决这个问题,你必须进行一些代码更改。

有很多方法可以解决这个问题,而且每种方法都有很多支持和反对。我会给你一个简单的黑客解决方案。如果您想要不同的东西,请告诉我,我会编写一个示例。

我还将假设您无法更改基于静态类的 ORM。

这是黑客方法,这是一种非常糟糕的做事方式,所以你知道。在你的类中有一个变量,它是你需要使用的 ORM 类的类名。这是 PHP 5.3 代码。

像这样:

<?php

class Bar {
    public static $ormName = 'FooModel';

    public static function doStuff()
    {
        $className = self::$ormName;
        echo $className::find(1), "\n";
    }
}

然后在您的 PHPUnit 测试中创建一个模拟。获取它的班级名称,在您的测试主题上设置该班级名称。现在您的测试对象将调用您的模拟。

有很多方法可以解决这个问题,但有些方法需要不直接使用类名。

【讨论】:

  • 谢谢!我想如果这是一个经典问题,除了弄清楚是否可以改变某些东西之外,没有好的答案?
  • 另一种选择是使用 runkit PECL 扩展并在您的引导代码中执行 runkit_method_redefine('FooModel', 'find', 'return "bar"');
猜你喜欢
  • 1970-01-01
  • 2021-02-10
  • 2016-09-13
  • 1970-01-01
  • 2012-07-06
  • 1970-01-01
  • 2011-06-04
  • 2013-03-13
  • 1970-01-01
相关资源
最近更新 更多