jeudi 28 janvier 2016

How to create global custom matchers in PHPSpec?

I'm testing with PHPSpec, and I've got custom matchers in my spec files that I don't want to have to repeat in every file in which they're used.

I want to be able to extend PHPSpec's behaviour and/or the behaviour of all my tests to use a global set of custom matchers.

The PHPSpec documentation shows how to create custom matchers (inline matchers): http://ift.tt/1lYte15

I have this inline matcher (as an example) in my 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;
            }
        ];
    }

This inline matcher example detects whether an array has an array as one of its values, and returns true or false.

As far as I can tell, PHPSpec calls getMatchers() when it constructs ThingImTestingSpec, if a getMatchers() method is present (otherwise PHPSpec ends up calling the empty getMatchers() method on ObjectBehavior.

What I've tried:

Create a CustomMatchers class and namespace it:

namespace SpecUtilities;

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

and add this to my spec file:

use SpecUtilities\CustomMatchers

and in the class itself:

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

but the return from getMatchers() when the tests are run doesn't get used for anything. PHPSpec only seems to be using the return from getMatchers() when it constructs the test (which makes sense - getMatchers() only returns an array of functions; it doesn't attach those functions to anything else, so PHPSpec isn't using them). I get the error

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

i.e. PHPSpec isn't loading the custom matchers.

All spec classes extend ObjectBehavior. I could add my getMatchers() function to PHPSpec's ObjectBehavior class, but I don't want to modify files under /vendor (PHPSpec is being pulled in using Composer). I could copy the vendor file and modify my own CustomObjectBehavior class, and make my spec classes extend that instead, but that will break the usability of PHPSpec's generator methods like phpspec describe SomeNewSpec (I'll have to change the class that new specs extend every time I generate a new spec).

Am I asking too much? Short of modifying ObjectBehavior itself to look for and load an external custom matchers file, and making a pull request for the PHPSpec repo itself, is there a way to load custom matchers without getting into bad practices?

Aucun commentaire:

Enregistrer un commentaire