2017-03-16 6 views
0

Zend Framework 3を使い始めて以来、コントローラのテストに問題がありました。私はPhpUnit 5.7でコントローラをテストしようとしています。私のコントローラはDoctrineのDoctrineObjectで水和されたZend Formに依存しています。
私はここに私に頭痛を与えている設定の最小限の例だ、可能な限りこのような単純なを入れしようとしている:フォーム付きコントローラのテストを書く

コントローラー:

class IndexController extends AbstractActionController { 
    private $form; 
    public function __construct(AlbumForm $form) { 
     $this->form = $form; 
    } 
    public function indexAction() { 
     return ['form' => $this-form]; 
    } 
} 

がControllerFactory:

class IndexControllerFactory implements FactoryInterface { 
    public function __invoke(ContainerInterface $container, ...) { 
     $formManager = $container->get('FormElementManager'); 
     return new IndexController($formManager->get(AlbumForm::class)); 
    } 
} 

対応するビューテンプレートalbums/index/index.phtml

<?php 
$this->form->prepare(); 
$this->form->setAttribute('action', $this->url(null, [], true)); 

$albumFieldset = $this->form->get('album'); 
?> 
<?= $this->form()->openTag($this-form) ?> 
    <div class="form-group"> 
     <?= $this->formRow($albumFieldset->get('name')) ?> 
    </div> 
<?= $this->form()->closeTag() ?> 

形式:

class AlbumForm extends Form { 
    public function init() { 
     $this->add([ 
      'name' => 'albumFieldset', 
      'type' => AlbumFieldset::class, 
      'options' => [ 
       'use_as_base_fieldset' => true, 
      ], 
     ]); 
    } 
} 

フィールドセット:

class AlbumFieldset extends Fieldset { 
    public function init() { 
     $this->add([ 
      'name' => 'name', 
      'type' => Text::class, 
      'options' => [ 
       'label' => 'Name of album', 
      ], 
     ]); 
    } 
} 

FieldsetFactory:今

class AlbumFieldsetFactory implements FactoryInterface { 
    public function __invoke(ContainerInterface $container, ...) { 
     $objectManager = $container->get(ObjectManager::class); 
     $fieldset = new AlbumFieldset(); 
     $fieldset->setHydrator(new DoctrineObject($objectManager)); 
     $fieldset->setObject(new Album()); 
     return $fieldset; 
    } 
} 

は、これまでのところ、すべてが素晴らしい働いています。
しかし、このためのテストを書くときには、問題が発生します。私がこれまでに持っているものを最初に見せてあげましょう。

class IndexControllerTest extends AbstractHttpControllerTestCase { 
    protected function setUp() { 
     parent::setUp(); 
     $this->configureServiceManager($this->getApplicationServiceLocator()); 
    } 
    private function configureServiceManager(ServiceManager $services) { 
     $services->setAllowOverride(true); 

     $services->setService(ObjectManager::class, $this->mockObjectManager()->reveal()); 
     $services->setService('FormElementManager', $this->mockFormManager()->reveal()); 

     $services->setAllowOverride(false); 
    } 
    private $objectManager; 
    private function mockObjectManager() { 
     $this->objectManager = $this->prophesize(ObjectManager::class); 
     return $this->objectManager; 
    } 
    private $formManager; 
    private function mockFormManager() { 
     $this->formManager = $this->prophesize(FormElementManager::class); 
     $this->formManager->get(AlbumForm::class)->willReturn($this->mockForm()->reveal()); 
     return $this->formManager; 
    } 
    private $form; 
    private function mockForm() { 
     $this->form = $this->prophesize(AlbumForm::class); 
     $this->form->prepare()->willReturn(null); 
     $this->form->setAttribute('action', Argument::type('string'))->willReturn(null); 
     $this->form->getAttributes()->willReturn([]); 
     $this->form->get('album')->willReturn($this->mockAlbumFieldset()->reveal()); 
     return $this->form; 
    } 
    private $albumFieldset; 
    private function mockAlbumFieldset() { 
     $this->albumFieldset = $this->prophesize(AlbumFieldset::class); 
     $this->albumFieldset->get('name')->willReturn($this->mockName()->reveal()); 
     return $this->albumFieldset; 
    } 
    private $name; 
    private function mockName() { 
     $this->name = $this->prophesize(Text::class); 
     $this->name->getLabel()->willReturn('label'); 
     $this->name->getLabelAttributes()->willReturn(['for' => 'name']); 
     $this->name->getLabelOption('disable_html_escape')->willReturn(false); 
     $this->name->getLabelOption('always_wrap')->willReturn(false); 
     $this->name->getLabelOption('label_position')->willReturn('prepend'); 
     $this->name->getName('album[name]'); 
     $this->name->getAttribute('type')->willReturn('text'); 
     $this->name->hasAttribute('id')->willReturn(true); 
     $this->name->getAttribute('id')->willReturn('name'); 
     $this->name->getAttributes([])->willReturn([]); 
     $this->name->getValue()->willReturn(null); 
     $this->name->getMessages()->willReturn([]); 
     return $this->name; 
    } 
} 

これは最終的にエラーなしで実行されます。しかし、最後のいくつかの方法、特にmockName()に注意を向けたいと思います。これらの定義のほとんどは完全にデフォルトであり、冒頭にAlbumFieldsetで指定されているものはほとんどありません(名前のみ)。 の場合はフォーム入力を書き留めるのは非常に面倒ですが、これを書くと実際に解決するよりも多くのエラーが発生します。たとえば、always_wrapの正しいラベルオプションが何であるかはまだ分かりません。私は実際にそのオプションについて気にしませんが、それ以外の場合は'Prophecy\Exception\Call\UnexpectedCallException' with message 'Method call: - getLabelOption("always_wrap") on Double\Zend\Form\Element\Text\P245 was not expected, expected calls were: ...で失敗するため、私はテストでそれについて何か書きます。

したがって、私はあなたに尋ねています:これについてもっと良い方法がありますか?自分のフィールドセットにあるすべてのフィールドに20以上の行を書き込むことを含まない方法。コントローラ/フィールドセット/ビューテンプレート(など)を書き直す必要がある場合、それはまったく問題ありません。

ご協力いただきありがとうございます。また、これは8年以上のプログラミングでフォーラムで何かを尋ねるのは初めてのことなので、不明な点があれば私にご相談ください。

ユアーズ ステファン

PS:私はすでに試してみましたが代わりに実際のフォームのIndexControllerヌルを与えることであり、それはフォームがnullであることを検出した場合、単純にビューテンプレートを中止。しかし、それほどセットアップをしなくても、私は基本的にビューテンプレートのロジックを避けていました。そのため、ビューテンプレートでエラーを検出できませんでした。それは私が望むものではありません。

答えて

0

編集IndexControllerTest:他の場所で保護されているようにプライベートに変更し、新しいフィールドに拡張します。それぞれの新しいコントローラは、parent :: methodname($ args)を呼び出すメソッドを上書きし、必要なコードを追加する必要があります。

関連する問題