5

Symfony2 で作成したコントローラーの PHP で小さなテストを行いました。

class DepositControllerTest extends WebTestCase {

    public function testDepositSucceeds() {

        $this->crawler = self::$client->request(
            'POST',
            '/deposit',
            array( "amount" => 23),
            array(),
            array()
        );

        $this->assertEquals(
            "Deposit Confirmation",
            $this->crawler->filter("title")->text());
    }
}

ここまでは、すべてが素晴らしかったです。ページの更新中に再送信の可能性を無効にしたいことに気付いたときに問題が発生しました。そこで、送信ごとにノンスを送信する小さなメカニズムを追加しました。

次のように機能します。

class ReplayManager {

    public function getNonce() {
        $uid = $this->getRandomUID();
        $this->session->set("nonce", $uid);
        return $uid;
    }

    public function checkNonce($cnonce) {

        $nonce = $this->session->get("nonce");

        if ($cnonce !== $nonce)
            return false;

        $this->session->set("nonce", null);
        return true;
    }
}

そのため、フォームを表示するときにノンスを取得し、送信するときにそれを消費するようにコントローラーを変更する必要がありました。

しかし今、これは問題を引き起こします。POST /depositどのナンスを送信すればよいかわからないため、リクエストを送信できません。GET /deposit最初にフォームをレンダリングするように要求し、フォームを設定して で使用することを考えましたPOSTが、Symfony2 セッションが PHPUnit で動作していないと思われます。

どうすればこの問題を解決できますか? Selenium テストには行きたくありません。かなり遅いので、たくさんのテストを書き直さなければならないことは言うまでもありません。

更新:リクエストに応じて、コントローラー コードの非常に単純化されたバージョンを追加します。

class DepositController extends Controller{

    public function formAction(Request $request){

        $this->replayManager = $this->getReplayManager();
        $context["nonce"] = $this->replayManager->getNonce();

        return $this->renderTemplate("form.twig", $context);
    }

    protected function depositAction(){

        $this->replayManager = $this->getReplayManager();
        $nonce               = $_POST["nonce"];

        if (!$this->replayManager->checkNonce($nonce))
            return $this->renderErrorTemplate("Nonce expired!");

        deposit($_POST["amount"]);

        return $this->renderTemplate('confirmation.twig');
    }

    protected function getSession() {
        $session = $this->get('session');
        $session->start();
        return $session;
    }

    protected function getReplayManager() {
        return new ReplayManager($this->getSession());
    }

}
4

2 に答える 2

1

ReplayManager が何をするのかはわかりませんが、「ナンス」を処理するのに適切なクラスではないように見えます。「ナンス」は最終的にセッションに格納され、セッションから取得されるため、コントローラーによって処理されるか、依存関係として渡される独自のクラスに抽象化される必要があります。これにより、テスト用に nonce (シチュエーション コメディのように聞こえます!) をモックすることができます。

私の経験では、テストの問題は実際にはコード設計の問題であり、匂いと見なされるべきです。この場合、問題はナンスを間違った場所で処理することに起因します。簡単なリファクタリング セッションで、テストの問題を解決できます。

于 2013-11-07T16:02:59.113 に答える
0

WebTestCase クライアント経由で PHPUnit から Symfony2 セッションにアクセスできます。私はこのようなものがうまくいくはずだと思います:

public function testDepositSucceeds() {

    $this->crawler = self::$client->request(
        'GET',
        '/deposit',
    );

    $session = $this->client->getContainer()->get('session');
    $nonce = $session->get('nonce');

    $this->crawler = self::$client->request(
        'POST',
        '/deposit',
        array("amount" => 23, "nonce" => $nonce),
        array(),
        array()
    );

    $this->assertEquals(
        "Deposit Confirmation",
        $this->crawler->filter("title")->text());
}

編集:

または、セッションからナンス値を取得する際に問題がある場合は、上記の GET と POST リクエストの間の 2 行を次のように置き換えてみてください。

$form = $crawler->selectButton('submit');
$nonce = $form->get('nonce')->getValue(); // replace 'nonce' with the actual name of the element
于 2013-11-07T16:09:08.940 に答える