PHPUnit:Mocking Symfony2 FormBuilderInterface - 类型提示问题

时间:2013-01-04 17:04:44

标签: php symfony phpunit

我正在尝试测试扩展Symfony\Component\Form\AbstractType的类,并且无法使用PHPUnit模拟对象测试所需的buildForm方法:

class PageType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('name', 'text');
    }

    // ...
 }

以下是一些示例测试代码:

public function testBuildForm()
{
    $form = new PageType($this->manager);
    $formBuilder = $this->getMock('Symfony\Component\Form\FormBuilderInterface');
    $form->buildForm($formBuilder, array());
}

不幸的是,对getMock()的调用失败了:

PHP Fatal error:  Class Mock_FormBuilderInterface_f36f83d4 must implement interface Traversable as part of either Iterator or IteratorAggregate in Unknown on line 0

我怀疑我可能会犯这个错误: https://github.com/sebastianbergmann/phpunit/issues/604

所以,我创建了一个解决问题的界面:

use Symfony\Component\Form\FormBuilderInterface;

interface FormBuilderInterfaceExtender extends \Iterator, FormBuilderInterface
{
}

并更改了我的测试代码:

public function testBuildForm()
{
    $form = new PageType($this->manager);
    $formBuilder = $this->getMock('Pwn\ContentBundle\Tests\Helper\FormBuilderInterfaceExtender');
    $form->buildForm($formBuilder, array());
}

现在我有一个FormBuilder实例,但PHP没有将其视为Symfony\Component\Form\FormBuilderInterface的实例,因此$form->buildForm()中的类型提示会出现此错误:

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

在其他情况下,当我使用模拟对象时,键入提示并instanceof正常工作,但这里没有:

var_dump($formBuilder);
var_dump($formBuilder instanceof \Symfony\Component\Form\FormBuilderInterface);

给出

class Mock_FormBuilderInterfaceExtender_76df04af#19 (1) {
  private $__phpunit_invocationMocker =>
  NULL
}
bool(false)

似乎我可以通过模拟实现接口的类来完成这项工作:

$formBuilder = $this->getMockBuilder('Symfony\Component\Form\FormBuilder')
                    ->disableOriginalConstructor()
                    ->getMock();

var_dump($formBuilder instanceof \Symfony\Component\Form\FormBuilderInterface);
// ^ gives bool(true)

但是,我应该能够使用界面本身吗?为什么扩展接口“丢失”类型提示?

2 个答案:

答案 0 :(得分:2)

每当您无法测试Symfony2接口时,请查看组件的Tests目录以查看是否有专门用于测试的模拟。测试接口扩展了真实的界面,并添加了使phpunit运行它们所需的任何调整。

在您的情况下,请尝试模仿Symfony\Component\Form\Tests\FormBuilderInterface

答案 1 :(得分:1)

似乎PHPUnit可以很好地模拟接口,并且扩展其他接口的接口没有问题。看看这个课程&测试用例

<强> NamespaceA.php

<?php
namespace Testing;
interface NamespaceA {}

<强> TestMockInterfaces.php

<?php
require 'NamespaceA.php';

interface Custom extends Testing\NamespaceA, Iterator, ArrayAccess {}

class TestMockInterfaces extends PHPUnit_Framework_TestCase
{
    public function testMocks()
    {
        $oSolidMock = $this->getMock('Iterator');
        $this->assertTrue($oSolidMock instanceof Iterator);

        $oSketchyMock = $this->getMock('Custom');
        $this->assertTrue($oSketchyMock instanceof Iterator);
        $this->assertTrue($oSketchyMock instanceof ArrayAccess);
        $this->assertTrue($oSketchyMock instanceof \Testing\NamespaceA);
    }
}

这通过100%,所以我怀疑还有其他事情发生。

模仿FormBuilderInterfaceExtender后尝试var_dump(class_implements($formBuilder));,看看它是否符合预期。