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であることを検出した場合、単純にビューテンプレートを中止。しかし、それほどセットアップをしなくても、私は基本的にビューテンプレートのロジックを避けていました。そのため、ビューテンプレートでエラーを検出できませんでした。それは私が望むものではありません。