Fandom

Wikia Developers Wiki

Nirvana/WikiaSuperFactory

< Nirvana

896pages on
this wiki
Add New Page
Talk0 Share

This class is still used but most of it's original features deprecated.  The F class still exists but F::build has been deprecated and all the utility functions are unused.  Wikia is using php_test_helpers and runkit now in our test framework, which allows us to override the new operator for mocking purposes without having to modify the style of PHP code that we write.  These docs are being updated to reflect the current state of things. 

The only function left in WikiaSuperFactory is the static helper to contruct a new WikiaApp object  F::app()

Old documentation follows:

WikiaSuperFactory class, aliased as F, provides easy to use solution for creating class instances and mocking such objects. It makes new() operator and static factory methods testable.

Mocking an object means creating class instance behaving as we want to, not as it was implemented. For instance PayflowApi mock would have all methods defined in class, but calling them would not result in connecting to PayPal API server. Instead predefined API response could be returned.

Building object

new operator

Common pitfal in writing testable code is using new() operator. Such code is not possible to unit test because there is no way of providing mocked object instead of creating new one. Consider the following example:

class Foo {
    function bar() {
        $cache = new Cache();
        return $cache->clean();
    }
}

Any test calling bar() method will create Cache class instance and call it's real clean() method. In most cases it's not desired to run real code of colaborating classes while unit testing, as it breaks isolation rule. In this particular case it could cause race condition problems (some other test might require some data to be cached and we clean it), create dependency on infrastructure (there's need to be real cache and it needs to work correctly) and so on. One of possible solutions is using factory instead of new() operator:

class Foo {
    function bar() {
        $cache = F::build('Cache');
        return $cache->clean();
    }
}

The key here is how build method works. It creates new object as usuall, unless an instance has been given.

Foo class test could look like:

class FooTest extends PHPUnit_Framework_TestCase {
    public function testEnsureThatBarMethodProxiesToCacheClean() {
        $cache = $this->getMock('Cache');
        $cache->expects($this->once())
              ->method('clean')
              ->will($this->returnValue(true));

        F::setInstance('Cache', $cache);

        $foo = new Foo();

        $this->assertTrue($foo->bar());
    }
}

In the test first we create Cache class mock and define it's behaviour. We expect it's method 'clean' to be called once and when called return a value, TRUE. Then we instruct factory to return our mock whenever factory is asked for Cache object to be build. To do so we use setInstance method. At the end of the test we create actuall Foo object, call it's bar method and check if it returned same value as Cache::clear.

Created mock will not use any caching services or resources. It will simply return enforced value when clean method is called. This way our test will not be dependent on possible caching infrastructure problems.

Passing constructor arguments

Second argument of build method is array of constructor arguments.

class Foo {
    function bar() {
        $cache = F::build('Cache', array('host' => 'localhost');
        $cache->clean();
    }
}

The above code is equivalent to:

class Cache {
    __construct($host) {}
}

class Foo {
    function bar() {
        $cache = new Cache('localhost');
        $cache->clean();
    }
}

Calling static factory methods

Factory methods can be called same way as constructor. Third argument of build() method is method name to call, by default __construct. Assuming newFromString is static factory method of Cache class the following is WikiaFactory way of calling it:

class Foo {
    function bar() {
        $cache = F::build('Cache', array('string' => 'host=localhost', 'newFromString');
        $cache->clean();
    }
}

The above example is equivalent to:

class Foo {
    function bar() {
        $cache = Cache::newFromString('host=localhost');
        $cache->clean();
    }
}

Static factory methods can be used by factory only when factory itself was configured to used them prior to calling.

Mocking production process

To force factory to return mock object instead of real object setInstance method can be used:

class FooTest extends PHPUnit_Framework_TestCase {
    public function testBar() {
        $mock = $this->getMock('Cache');
        F::setInstance('Cache', $mock);
    }
}

Since now all attempts to create Cache object using WikiaSuperFactory will result in returning $mock object instead of creating new one (useful for unit testing).

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.