I am trying to test a class that extends Symfony\Component\Form\AbstractType
, and having trouble testing the required buildForm
method with a PHPUnit mock object:
class PageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text');
}
// ...
}
Here's some example test code:
public function testBuildForm()
{
$form = new PageType($this->manager);
$formBuilder = $this->getMock('Symfony\Component\Form\FormBuilderInterface');
$form->buildForm($formBuilder, array());
}
Unfortunately the call to getMock()
fails:
PHP Fatal error: Class Mock_FormBuilderInterface_f36f83d4 must implement interface Traversable as part of either Iterator or IteratorAggregate in Unknown on line 0
I suspect I might have fallen foul of this bug: https://github.com/sebastianbergmann/phpunit/issues/604
So, I have created an interface to work around the problem:
use Symfony\Component\Form\FormBuilderInterface;
interface FormBuilderInterfaceExtender extends \Iterator, FormBuilderInterface
{
}
and changed my test code:
public function testBuildForm()
{
$form = new PageType($this->manager);
$formBuilder = $this->getMock('Pwn\ContentBundle\Tests\Helper\FormBuilderInterfaceExtender');
$form->buildForm($formBuilder, array());
}
Now I have a FormBuilder instance, but PHP doesn't see it as an instance of Symfony\Component\Form\FormBuilderInterface
, so the type hinting in $form->buildForm()
gives this error:
Argument 1 passed to Pwn\ContentBundle\Form\Type\PageType::buildForm() must be an instance of Symfony\Component\Form\FormBuilderInterface, instance of Mock_FormBuilderInterfaceExtender_3527f313 given
In other cases when I've used a mock object, type hinting and instanceof
work correctly, but here it doesn't:
var_dump($formBuilder);
var_dump($formBuilder instanceof \Symfony\Component\Form\FormBuilderInterface);
gives
class Mock_FormBuilderInterfaceExtender_76df04af#19 (1) {
private $__phpunit_invocationMocker =>
NULL
}
bool(false)
It seems I can make this work by mocking a class that implements the interface:
$formBuilder = $this->getMockBuilder('Symfony\Component\Form\FormBuilder')
->disableOriginalConstructor()
->getMock();
var_dump($formBuilder instanceof \Symfony\Component\Form\FormBuilderInterface);
// ^ gives bool(true)
However, should I be able to use the interface itself? Why does extending an interface 'lose' the type hinting?