Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/symfony/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Forms PHPUnit:使用存储在Symfony2中的会话变量测试表单提交_Forms_Symfony_Phpunit_Php - Fatal编程技术网

Forms PHPUnit:使用存储在Symfony2中的会话变量测试表单提交

Forms PHPUnit:使用存储在Symfony2中的会话变量测试表单提交,forms,symfony,phpunit,php,Forms,Symfony,Phpunit,Php,我用PHP为我用Symfony2编写的控制器做了一个小测试: class DepositControllerTest extends WebTestCase { public function testDepositSucceeds() { $this->crawler = self::$client->request( 'POST', '/deposit', array( "amou

我用PHP为我用Symfony2编写的控制器做了一个小测试:

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());
    }
}
到目前为止,一切都很好。当我意识到我想在刷新页面时禁用可能的重新提交时,问题开始了。所以我添加了一个小机制,在每次提交时发送nonce

它的工作原理如下:

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;
    }
}
因此,我必须在显示表单时对控制器进行mofidy,以获取nonce,并在提交时使用它

但现在这带来了一个问题。我不能请求邮寄/寄存,因为我不知道要寄出什么临时邮件。我想先请求
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());
    }

}

我不确定ReplayManager做什么,但在我看来,它似乎不是处理“nonce”的正确类。由于“nonce”最终存储在会话中并从会话中检索,因此它应该由控制器处理或抽象为自己的类,然后作为依赖项传入。这将允许您模拟nonce(听起来像情景喜剧!)进行测试


根据我的经验,测试中的问题实际上是代码设计的问题,应该被视为一种气味。在这种情况下,您的问题源于在错误的位置处理临时事件。快速重构会话应该可以解决您的测试问题。

可以通过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());
}
编辑:

或者,如果从会话获取nonce值时出现问题,您可以尝试将上面GET和POST请求之间的两行替换为:

$form = $crawler->selectButton('submit');
$nonce = $form->get('nonce')->getValue(); // replace 'nonce' with the actual name of the element

你能出示你的控制器代码吗?ReplayManager还在做什么?我认为您的问题在于关注点分离,您的控制器代码可能有助于确认这一点。完成后,我编写了一个非常简化的控制器版本为什么不使用?如果用户在页面加载指令前按F5,PRG会保护我吗?同意-就我而言,任何需要会话对象的事情都应该在控制器中处理。然而,我不认为这是造成OP在这个例子中的问题的原因。好吧,replayManager是由控制器处理的,所以它不是一样的吗?我已经更新了控制器,以显示我如何通过会话。我试过了!问题是,当我执行
POST
时,在第一页上创建的nonce不在第二页上。这就是我对不在phmm上工作的PHP会话的意思。我确实成功地在单元测试中检索到了会话值,但我也对它有一个评论“//如果我们稍后得到它,它是空的!”因此出现了一个问题。话虽如此,该项目仍在Symfony 2.0.4上,因此情况可能已经发生了变化——我希望情况会好转,但可能不会?