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

时间:2016-01-28 23:30:31

标签: php unit-testing tdd phpspec

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

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

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

我的ThingImTestingSpec类中有这个内联匹配器(作为示例):

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;
            }
        ];
    }

此内联匹配器示例检测数组是否将数组作为其值之一,并返回true或false。

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

我尝试了什么:

创建一个CustomMatchers类并命名它:

namespace SpecUtilities;

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

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

use SpecUtilities\CustomMatchers

并且在班级本身:

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

但运行测试时getMatchers()的返回不会被用于任何事情。 PHPSpec似乎只是在构造测试时使用getMatchers()的返回值(这是有道理的 - getMatchers()只返回一个函数数组;它不会将这些函数附加到其他任何函数上,因此PHPSpec不是不使用它们。我收到了错误

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

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

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

我问得太多了吗?如果没有修改ObjectBehavior本身来查找和加载外部自定义匹配器文件,并为PHPSpec repo本身提出拉取请求,是否有办法加载自定义匹配器而不会陷入不良做法?

2 个答案:

答案 0 :(得分:1)

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

  

允许通过配置

全局注册自定义phpspec匹配器

答案 1 :(得分:0)

有两种方法可以获得所需的结果:

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

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

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