如何在PHP中存根这个函数

如何在PHP中存根这个函数,php,phpunit,stubbing,Php,Phpunit,Stubbing,我想测试以下课程: <?php namespace Freya\Component\PageBuilder\FieldHandler; use Freya\Component\PageBuilder\FieldHandler\IFieldHandler; /** * Used to get a set of non empty, false or null fields. * * The core purpose is to use this class to determin

我想测试以下课程:

<?php

namespace Freya\Component\PageBuilder\FieldHandler;

use Freya\Component\PageBuilder\FieldHandler\IFieldHandler;

/**
 * Used to get a set of non empty, false or null fields.
 *
 * The core purpose is to use this class to determine that A) Advanced Custom Fields is installed
 * and B) that we get back a set of fields for a child page.
 *
 * The cavete here is that this class requires you to have child pages that then have Custom Fields that
 * you want to display on each of those pages. getting other page information such as content, title, featured image
 * and other meta boxes is left ot the end developer.
 *
 * @see Freya\Component\PageBuilder\FieldHandler\IFieldHandler
 */
class FieldHandler implements IFieldHandler {

    /**
     * {@inheritdoc}
     *
     * @return bool
     */
    public function checkForAFC() {
        return function_exists("register_field_group");
    }

    /**
     * {@inheritdoc}
     *
     * @param $childPageID - the id of the child page who may or may not have custom fields.
     * @return mixed - Null or Array
     */
    public function getFields($childPageId) {
        $fieldsForThisPage = get_fields($childPageId);

        if (is_array($fieldsForThisPage)) {
            foreach ($fieldsForThisPage as $key => $value) {
                if ($value === "" || $value === false || $value === null) {
                    unset($fieldsForThisPage[$key]);
                }
            }

            return $fieldsForThisPage;
        }

        return null;
    }
}

您可以在全局命名空间中定义这样的函数。请看以下示例:

namespace {
    function getFields($pageId) {
        return array($pageId);
    }
}

namespace MyNamespace {
    class MyClass
    {
        public function foo(){
            var_dump(getFields(5));
        }
    }

    $obj = new MyClass();
    $obj->foo();
}
以下是输出:

array(1) {
  [0]=>
  int(5)
}
唯一的问题是这个函数将一直存在到脚本结束。要解决此问题,可以将拆卸方法与runkit库一起使用:

允许您删除用户定义的函数。 不幸的是,这个库不存在于Windows上,因此,您将无法删除该定义,并且可以考虑孤立地运行测试。

编辑: 您也可以考虑使用这个库(它也依赖于RunKIT):

您可以在这里对非限定函数名
get_fields()
使用技巧。由于没有使用完全限定的函数名
\get_fields()
PHP将首先尝试在当前名称空间中查找函数,然后返回全局函数名

有关限定和非限定的定义,请参见:(它类似于绝对和相对文件名)

因此,您需要做的是在类的名称空间中定义函数,以及您的测试用例,如下所示:

namespace Freya\Component\PageBuilder\FieldHandler;

function get_fields()
{
    return ['X'];
}

class FieldHandlerTest extends \PHPUnit_Test_Case
{
    ...
}
补充说明:
  • 您可以对核心功能执行相同的操作,如下所述:
  • 这个技巧只适用于函数,而不适用于类。全局命名空间中的类必须始终使用前导反斜杠引用

为什么要存根
获取\u字段
?因为我无法确定它是否存在于此实例中。此函数属于WordPress插件,为了进行此测试,将不会安装该插件。所以我需要存根这个函数,让它为test@RonniSkansing返回一个特定的值,就像例子9.2@RonniSkansing,它要求我将这个函数包装在另一个函数中,然后调用它。。。如果不将函数包装到特定于类的函数中,就没有办法将函数本身存根吗?您的测试是什么样子的?你在做单元测试吗?您需要模拟一个类来访问它的存根方法,这通常是在使用依赖项进行测试时所做的。如果
get\u fields()
确实存在(“无法重新定义函数”),并且我在回答中提到了它,那么就不能使用原始依赖项的模拟切换依赖项。runkit库或使用它的整个mock函数repo。这将解决这个问题。除非您使用的是Windows,否则您可能会运气不佳。但是,只要您不试图为同一类中的不同测试重新定义此方法,您的解决方案似乎更合适。