How to test factory classes?
design-patterns, php, testing, unit-testing
Solution
Factories are inherently testable, you are just trying to get too tight of control over the implementation.
You would check that you get an instance of your class via `$this->assertInstanceOf()`. Then with the resulting object, you would make sure that properties are set properly. For this you could use any public accessor methods or use `$this->assertAttribute*` methods that are available in PHPUnit.
http://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.assertions.assertEquals
Many of the common assertions also have the ability to check attributes for protected and private properties.
I wouldn't specify the classname in your parameter list, as your usage is that the factory will only return one type and it is only the dependencies that are changed. Making it return a mock object type is unnecessary and makes your test more complicated.
The test would end up looking like this:
public function testBuild() {
$factory = new MyBuilder();
//I would likely put the following into a data provider
$param1 = 'foo';
$param2 = 'bar';
$depen1 = 'boo';
$depen2 = 'baz';
$depen3 = 'boz';
$object = $factory->build($param1, $param2);
$this->assertInstanceOf('MyClass', $object);
//Check the object definition
//This would change depending on your actual implementation of your class
$this->assertAttributeEquals($depen1, 'attr1', $object);
$this->assertAttributeEquals($depen2, 'attr2', $object);
$this->assertAttributeEquals($depen3, 'attr3', $object);
}
You are now making sure that your factory returns a proper object. First by making sure that it is of the proper type. Then by making sure that it was initialized properly.
You are depending upon the existence of `MyClass` for the test to pass but that is not a bad thing. Your factory is intended to created `MyClass` objects so if that class is undefined then your test should definitely fail.
Having failing tests while your developing is also not a bad thing.
Problem
Given this class: ``` class MyBuilder { public function build($param1, $param2) { // build dependencies ... return new MyClass($dep1, $dep2, $dep3); } } ``` How can I unit test this class? Unit-testing it means I want to test its behavior, so I want to test it builds my object with the correct dependencies. However, the `new` instruction is hardcoded and I can't mock it. For now, I've added the name of the class as a parameter (so I can provide the class name of a mock class), but it's ugly: ``` class MyBuilder { public function build($classname, $param1, $param2) { // build dependencies ... return new $classname($dep1, $dep2, $dep3); } } ``` Is there a clean solution or design pattern to make my factories testable?