Welcome to Abdul Malik Ikhsan's Blog

Testing Lazy Load with ReflectionClass

Posted in Tutorial PHP by samsonasik on January 2, 2015

One of the benefits by using ReflectionClass is when dealing with testing Lazy load. The flow is get the property, use its instance as ReflectionProperty to make it accessible, and set the property value via setValue().
Ok, let’s give a try.
I’ve a “Bar” class that looks like the following :

namespace Samsonasik\TutorialLazyLoading;

/**
 * @author Abdul Malik Ikhsan <samsonasik@gmail.com>
 */
class Bar
{
    /**
     * @var Foo
     */
    private $foo;
    
    /**
     * Get foo property
     * @return Foo
     */
    public function getFoo()
    {
        if (!$this->foo) {
            $this->foo = new Foo;
            return $this->foo;    
        }
        
        return $this->foo;
    }
}

When you call getFoo() in unit test with :

use Samsonasik\TutorialLazyLoading\Bar;
use Samsonasik\TutorialLazyLoading\Foo;

// ...
    protected function setUp()
    {
        $this->bar = new Bar;   
    }
    
    public function testGetFooNotInitializedYet()
    {
        $this->assertInstanceOf(
            Foo::class, /** use 'Samsonasik\TutorialLazyLoading\Foo' for PHP <=5.4 **/
            $this->bar->getFoo()
        );
    }
// ...

, you will get coverage only if (!$this->foo) { block like this :
half-phpunit-test-coverage-on-lazyload

Time to do ReflectionClass in action!, add new test for it’s needed.

use ReflectionClass;
use Samsonasik\TutorialLazyLoading\Bar;
use Samsonasik\TutorialLazyLoading\Foo;

// ...
    protected function setUp()
    {
        $this->bar = new Bar;   
    }
    public function testGetFooNotInitializedYet() { // ...  }
    
    public function testGetFooWithAlreadyInialized()
    {
        $class = new ReflectionClass(
            Bar::class /** use 'Samsonasik\TutorialLazyLoading\Bar' for PHP <=5.4 **/
        );
        $property = $class->getProperty('foo');
        $property->setAccessible(true);
        $property->setValue($this->bar, new Foo);
        
        $this->assertInstanceOf(
            Foo::class, /** use 'Samsonasik\TutorialLazyLoading\Foo' for PHP <=5.4 **/
            $this->bar->getFoo()
        );
    }
// ...   

And yay! You now get fully tested :
full-phpunit-test-coverage-on-lazyload

Note :
As @ocramius suggestion, there is an easier way to do it by calling the method twice ;).

Want to grab it ? You can grab from my repository : https://github.com/samsonasik/TutorialLazyLoading .

References :
1. http://www.mikeyd.com.au/2011/01/20/how-to-use-phps-reflectionclass-to-test-private-methods-and-properties-with-phpunit/