How to achieve test isolation with Symfony forms and data transformers? How to achieve test isolation with Symfony forms and data transformers? symfony symfony

How to achieve test isolation with Symfony forms and data transformers?


First of all, I have next to no experience with Symfony. However, I think you missed a third option there. In Working Effectively with Legacy Code, Michael Feathers outlines a way to isolate dependencies by using inheritance (he calls it "Extract and Override").

It goes like this:

class HiddenEntityType extends AbstractType{    /* stuff */    public function buildForm(FormBuilderInterface $builder, array $options)    {        if ($options['multiple']) {            $builder->addViewTransformer(                $this->createEntitiesToPrimaryKeysTransformer($options)            );        }    }    protected function createEntitiesToPrimaryKeysTransformer(array $options)    {        return new EntitiesToPrimaryKeysTransformer(            $this->em->getRepository($options['class']),            $options['get_pk_callback'],            $options['identifier']        );    }}

Now to test, you create a new class, FakeHiddenEntityType, that extends HiddenEntityType.

class FakeHiddenEntityType extends HiddenEntityType {    protected function createEntitiesToPrimaryKeysTransformer(array $options) {        return $this->mock;    }    }

Where $this->mock obviously is whatever you need it to be.

The two most prominent advantages are that there are no factories involved, thus complexity is still encapsulated, and there is virtually no chance that this change breaks existing code.

The disadvantage being that this technique requires an extra class. More importantly, it requires a class that knows about the internals of the class under test.


To avoid the extra class, or rather hide the extra class, one could encapsulate it in a function, creating an anonymous class instead (support for anonymous classes was added in PHP 7).

class HiddenEntityTypeTest extends TestCase{    private function createHiddenEntityType()    {        $mock = ...;  // Or pass as an argument        return new class extends HiddenEntityType {            protected function createEntitiesToPrimaryKeysTransformer(array $options)            {                return $mock;            }            }    }    public function testABC()    {        $type = $this->createHiddenEntityType();        /* ... */    }}