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:
- Placing the class variables within a constructor – still can't be accessed by the examples
- Using
beConstructedWith
– requires altering the class under test just so it can be tested. Not a clean solution. - When the common objects I want to reference are database records, I can reference them by id (or other properties) using Eloquent, building a collection or class object from the Model each time. This works, but is time-consuming, as I need to build the collection or object in every spec function. I'd like to build these collections and objects once, when the spec class is instantiated, and reference them throughout the class.
Things I haven't tried yet:
- Creating a third object outside the scope of both the spec class and the class under test to house the universal objects and variables, which can be accessed by the spec class methods (the examples) at runtime. This solution could work, but it adds a layer to the specs that I'd like to avoid if there's a cleaner solution.
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