4

現在、Symfony2 を使用しており、プロジェクトを PHPUnit でテストしています。フォームが間違ったパラメーターで送信された場合、または URL が完全でない場合に、例外をテストしたいと考えています。

Symfony2 と PHPUnit のドキュメントを調べましたが、そのためのクラス/メソッドが見つかりませんでした。

フォームのアクションの値を変更するにはどうすればよいですか? PHPUnit を使用して、作成されたレポートが最新のものになり、コードのカバレッジを確認できるようにしたいと考えています。

編集:

私の質問を明確にするために、いくつかの新しいコンテンツがあります。コントローラーで「>」で始まる行をテストするにはどうすればよいですか? ( throw $this->createNotFoundException('Unable to find ParkingZone entity.');)

ユーザーがアクション リンクを変更すると、コントローラーでプロセスが例外 (または、このアクションが選択された場合はエラー メッセージ) を通過します。このケースをテストするにはどうすればよいですか?

コントローラ

/**
 * Edits an existing ParkingZone entity.
 *
 * @Route("/{id}/update", name="parkingzone_update")
 * @Method("post")
 * @Template("RatpGarageL1Bundle:ParkingZone:edit.html.twig")
 */
public function updateAction($id)
{
    $em = $this->getDoctrine()->getEntityManager();

    $entity = $em->getRepository('RatpGarageL1Bundle:ParkingZone')->find($id);

    if (!$entity) {
>        throw $this->createNotFoundException('Unable to find ParkingZone entity.');
    }

    $editForm   = $this->createForm(new ParkingZoneType(), $entity);
    $deleteForm = $this->createDeleteForm($id);

    $request = $this->getRequest();

    $editForm->bindRequest($request);

    if ($editForm->isValid()) {
        $em->persist($entity);
        $em->flush();

        return $this->redirect($this->generateUrl('parkingzone_edit', array('id' => $id)));
    }

    return array(
        'entity'      => $entity,
        'edit_form'   => $editForm->createView(),
        'delete_form' => $deleteForm->createView(),
    );
}

意見:

<form action="{{ path('parkingzone_update', { 'id': entity.id }) }}" method="post" {{ form_enctype(form) }}>
    <div class="control-group">
        {{ form_label(form.name, 'Name', { 'attr': {'class': 'control-label'} } ) }}
        <div class="controls error">
            {{ form_widget(form.name, { 'attr': {'class': ''} } ) }}
            <span class="help-inline">{{ form_errors(form.name) }}</span>
        </div>
    </div>
    <div class="control-group">
        {{ form_label(form.orderSequence, 'Rang', { 'attr': {'class': 'control-label'} } ) }}
        <div class="controls error">
            {{ form_widget(form.orderSequence, { 'attr': {'class': ''} } ) }}
            <span class="help-inline">{{ form_errors(form.orderSequence) }}</span>
        </div>
    </div>
    <div class="control-group">
        {{ form_label(form.image, 'Image', { 'attr': {'class': 'control-label'} } ) }}
        <div class="controls error">
            {{ form_widget(form.image, { 'attr': {'class': ''} } ) }}
            <span class="help-inline">{{ form_errors(form.image) }}</span>
        </div>
    </div>
    {{ form_rest(form) }}
    <div class="form-actions">
        <button type="submit" class="btn btn-primary">Enregistrer</button>
        <a href="{{ path('parkingzone') }}" class="btn">Annuler</a>
    </div>
</form>
4

3 に答える 3

3

symfony 自体には、html (小枝ファイル) で設定されているフォームのアクションを操作できるオブジェクトはありません。ただし、twig は、twig ファイルでフォームのアクションを動的に変更する機能を提供します。

基本的なアプローチは、コントローラーが render 呼び出しを介して twig ファイルにパラメーターを渡すことです。次に、小枝ファイルはこのパラメーターを使用してフォームアクションを動的に設定できます。コントローラーがセッション変数を使用してこのパラメーターの値を決定する場合、テスト プログラムでこのセッション変数の値を設定することにより、テスト専用のフォーム アクションを設定できます。

たとえば、コントローラーでは次のようになります。

public function indexAction()
{
    $session = $this->get('session');
    $formAction = $session->get('formAction');
    if (empty($formAction)) $formAction = '/my/normal/route';

    ...

    return $this->render('MyBundle:XXX:index.html.twig', array(
        'form' =>  $form->createView(), 'formAction' => $formAction)
    );
}

そして、小枝ファイルで:

<form id="myForm" name="myForm" action="{{ formAction }}" method="post">
...
</form>

そして、テストプログラムで:

$client = static::createClient();
$session = $client->getContainer()->get('session');
$session->set('formAction', '/test/route');
$session->save();

// do the test

これが唯一の方法ではなく、さまざまな可能性があります。たとえば、セッション変数は $testMode で、この変数が設定されている場合、フォームは $testMode = true をレンダリング呼び出しに渡します。次に、twig ファイルは、testMode 変数の値に応じて、フォーム アクションを 2 つの値のいずれかに設定できます。

于 2012-07-18T09:01:20.350 に答える
1

@redbirdo の最後の回答のおかげで、コントローラーを台無しにすることなく解決策を見つけました。テンプレートの数行だけを変更しました。

コントローラーテスト

public function testUpdate()
{
    $client = static::createClient();
    $session = $client->getContainer()->get('session');
    $session->set('testActionForm', 'abc');
    $session->save();       // This line is important or you template won't see the variable

    // ... tests
}

意見

{% if app.session.has('testActionForm') %}
    {% set actionForm = path('parkingzone_update', { 'id': app.session.get('testActionForm') }) %}
{% else %}
    {% set actionForm = path('parkingzone_update', { 'id': entity.id }) %}
{% endif %}

<form action="{{ actionForm }}" {{ form_enctype(form) }} method="POST" class="form-horizontal">
// ... rest of the form
于 2012-07-18T11:19:06.170 に答える
1

Symfony2 では、個々のクラスの単体テストとアプリケーションの動作の機能テストを区別しています。単体テストは、クラスを直接インスタンス化し、そのメソッドを呼び出すことによって実行されます。機能テストは、要求をシミュレートし、応答をテストすることによって実行されます。詳細については、 symfony のテストを参照してください。

フォーム送信は、コンテナーのコンテキストで常に動作する Symfony コントローラーによって処理されるため、機能的にのみテストできます。symfony の機能テストは WebTestCase クラスを拡張する必要があります。このクラスは、URL の要求、リンクのクリック、ボタンの選択、およびフォームの送信に使用されるクライアントへのアクセスを提供します。これらのアクションは、HTML 応答を表すクローラー インスタンスを返します。これは、応答に予期されるコンテンツが含まれていることを確認するために使用されます。

機能テストはユーザーとの対話をカバーするため、単体テストを実行するときに例外がスローされることをテストすることだけが適切です。ユーザーは、例外がスローされたことを認識してはなりません。したがって、最悪のシナリオは、例外が Symfony によってキャッチされ、実稼働環境でユーザーにキャッチオール応答「おっと、エラーが発生しました」(または同様のカスタマイズされたメッセージ) が表示されることです。ただし、これは実際には、ユーザーがアプリケーションを正しく使用していないためではなく、アプリケーションが壊れている場合にのみ発生するはずです。したがって、これは通常、機能テストでテストされるものではありません。

質問で言及された最初のシナリオについて - 間違ったパラメータでフォームを送信します。この場合、入力のどこが間違っているかを示すエラー メッセージがユーザーに表示されます。理想的には、コントローラーは例外をスローすべきではありませんが、symfony の検証を使用して、必要に応じて各フィールドの横にエラー メッセージを自動的に生成する必要があります。エラーがどのように表示されるかに関係なく、フォーム送信に対する応答に予想されるエラーが含まれていることを確認することで、これをテストできます。例えば:

class MyControllerTest extends WebTestCase
{
    public function testCreateUserValidation()
    {
        $client = static::createClient();
        $crawler = $client->request('GET', '/new-user');
        $form = $crawler->selectButton('submit')->form();
        $crawler = $client->submit($form, array('name' => '', 'email' => 'xxx'));
        $this->assertTrue($crawler->filter('html:contains("Name must not be blank")')->count() > 0,
                          "Page contains 'Name must not be blank'");
        $this->assertTrue($crawler->filter('html:contains("Invalid email address")')->count() > 0,
                          "Page contains 'Invalid email address'");
    }
}

2 番目のシナリオについて - URL が完全でない場合。Symfony では、定義されたルートに一致しない URL はすべて NotFoundHttpException になります。開発中は、「"GET /xxx" のルートが見つかりません」などのメッセージが表示されます。本番環境では、キャッチオール「おっと、エラーが発生しました」という結果になります。応答に「ルートが見つかりません」が含まれていることを開発中にテストすることは可能です。しかし、実際にはこれをテストする意味はありません。これは Symfony フレームワークによって処理されるため、当然のことです。

編集:

オブジェクトを識別する無効なデータが URL に含まれているシナリオについて。これは、単体テスト プログラムで次のように (開発中に) テストできます。

$client = static::createClient();

$page = $client->request('GET', '/update/XXX');
$exceptionThrown = ($page->filter('html:contains("NotFoundException")')->count() > 0) && ($page->filter('html:contains("Unable to find ParkingZone entity")')->count() > 0);
$this->assertTrue($exceptionThrown, "Exception thrown 'Unable to find ParkingZone entity'");

特定のタイプ/メッセージではなく、例外がスローされたことをテストしたいだけの場合は、「例外」の html をフィルタリングするだけです。本番環境では、ユーザーには「エラーが発生しました」というメッセージしか表示されず、「例外」という単語は表示されないことに注意してください。

于 2012-07-17T10:45:35.640 に答える