如何在 PHPSpec 中创建全局自定义匹配器?

How to create global custom matchers in PHPSpec?

我正在使用 PHPSpec 进行测试,我的规范文件中有自定义匹配器,我不想在使用它们的每个文件中都重复这些匹配器。

我希望能够扩展 PHPSpec 的行为 and/or 我所有测试的行为以使用一组全局自定义匹配器。

PHPSpec 文档显示了如何创建自定义匹配器(内联匹配器): http://phpspec.readthedocs.org/en/latest/cookbook/matchers.html#inline-matcher

我的 ThingImTestingSpec class:

中有这个内联匹配器(作为示例)
public function getMatchers()
    {
        return [
            'haveSecondLevelKey' => function ($subject, $key) {
                foreach ($subject as $first_level_key => $second_level_array)
                {
                    if (is_array($second_level_array))
                    {
                        return array_key_exists($key, $second_level_array);
                    }
                }
                return FALSE;
            }
        ];
    }

这个内联匹配器示例检测一个数组是否有一个数组作为它的值之一,并且 return 是真还是假。

据我所知,PHPSpec 在构造 ThingImTestingSpec 时调用 getMatchers(),如果存在 getMatchers() 方法(否则 PHPSpec 最终会调用空的 getMatchers() ObjectBehavior.

上的方法

我尝试过的:

创建一个 CustomMatchers class 并为其命名:

namespace SpecUtilities;

class CustomMatchers
{
    public static function getMatchers()
    { ... }
}

并将其添加到我的规范文件中:

use SpecUtilities\CustomMatchers

并且在 class 本身:

function it_pulls_in_custom_matchers()
{
    CustomMatchers::getMatchers();
}

但是 getMatchers() 中的 return 当测试为 运行 时不会用于任何事情。 PHPSpec 在构建测试时似乎只使用 getMatchers() 中的 return (这很有意义 - getMatchers() 只是 return 一个函数数组;它不附加这些函数用于其他任何东西,所以 PHPSpec 没有使用它们)。我收到错误

no haveSecondLevelKey([array:1]) matcher found for [array:14].

即PHPSpec 未加载自定义匹配器。

所有规范 class 扩展 ObjectBehavior。我可以将我的 getMatchers() 函数添加到 PHPSpec 的 ObjectBehavior class,但我不想修改 /vendor 下的文件(使用 Composer 引入 PHPSpec)。我可以复制供应商文件并修改我自己的 CustomObjectBehavior class,并使我的规范 classes 扩展它,但这会破坏 PHPSpec 生成器方法的可用性,如 phpspec describe SomeNewSpec(每次生成新规格时,我都必须更改新规格扩展的 class)。

我是不是要求太多了?除了修改 ObjectBehavior 本身以查找和加载外部自定义匹配器文件,并为 PHPSpec 存储库本身发出拉取请求外,是否有一种方法可以加载自定义匹配器而不会陷入不良做法?

有两种方法可以得到你想要的结果:

a) 扩展 ObjectBehaviour 并添加新的默认 getMatchers,然后扩展新的 class 而不是 ObjectBehaviour。您可以使用自定义模板来确保 describe 然后生成 classes 扩展正确的对象(查看 PhpSpec 本身如何使用自定义模板 https://github.com/phpspec/phpspec/tree/master/.phpspec

b) 将您的匹配器编写为实现 PhpSpec\Matcher\MatcherInterface 的对象,然后编写一个扩展,将您的自定义匹配器注册到 PhpSpec。这比较复杂,需要了解 Matchers 的注册方式。

我们正在考虑如何在未来的版本中使这更容易,可能是通过一些配置设置。

为此,我使用了扩展程序 "phpspec-matcher-loader-extension" -- 它对我来说效果很好。来自描述:

Allows custom phpspec matchers to be registered globally via configuration