laravelfactoryphpspec

How to create class variables in a PHPSpec spec file that can be used for all examples in the spec


I have a PHPSpec class with many examples. I want to be able to create class variables in the spec class that can be used by any example function in the class.

Below is a very simplified version:

class ThingImTestingSpec extends ObjectBehavior
{
    private $common_variables_array = [
        'property_1' => value_1,
        'property_2' => 'Value 2'
    ];

    function it_finds_a_common_property()
    {
        $object_1 = new ConstructedObject;

        $this->find_the_common_property($object_1)->shouldReturn($this->common_variables_array['property_1']);
    }
}

The issue lies in how PHPSpec (cleverly) instantiates and references the class under test. References to $this in the spec methods actually refer to the test object, not the spec class itself.

But that means that trying to reference class variables using $this->class_variable references class variables on the test object, not the spec.

So. How to create a set of variables in the scope of the spec class itself that can be accessed by the examples at runtime?

Things I've tried:

Things I haven't tried yet:

NB: I'm not looking for "alternatives" to going about testing in the way outlined above, unless they still suit the broader needs. The example is extremely pared down. In practice, I'm extending LaravelObjectBehavior (https://github.com/BenConstable/phpspec-laravel), creating records in a test database using the spec's constructor via Factory and Faker classes (https://github.com/thephpleague/factory-muffin), and destroying them after the test (League\FactoryMuffin\Facade::deleteSaved() in the spec's destructor). I want to be able to reference objects represented by the Model (and created by FactoryMuffin) in any number of spec functions, so I don't have to recreate these objects and collections in every spec function. And yes, I'm aware that this steps outside the realm of "spec" testing, but when an app is tethered to a model, objects that interact with the data layer are still "speccable", it can be argued.

I'm currently using phpspec 2.2.1 and Laravel 4.2


Solution

  • We currently use PHPSpec v3 in our software. Please use let method to declare common things. Quick example:

    <?php
    
    class ExampleSpec extends \PhpSpec\ObjectBehavior
    {
        private $example; // private property in the spec itself
    
        function let()
        {
            $this->example = (object) ['test1' => 'test1']; // setting property of the spec
            parent::let();
        }
    
        function it_works()
        {
            var_dump($this->example); // will dump: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
        }
    
        function it_works_here_as_well()
        {
            var_dump($this->example); // will dump same thing as above: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
            $this->example = (object) ['test2' => 'test2']; // but setting here will be visible only for this example
        }
    
        function it_is_an_another_example()
        {
            var_dump($this->example); // will dump same thing first two examples: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
        }
    }