Zend_Form で CSRF 非表示のハッシュ要素を使用し、ログインの単体テストを試みていますが、その要素を含める単体テストを作成する方法がわかりません。ドキュメントを見て、見つけられる限り多くのチュートリアルを読みました。私もそれらすべてをおいしくしましたが、誰もこれについて言及していません。
5 に答える
csrf 値は、フォームがレンダリングされるたびに生成されます。フォームの隠し要素には、その値が事前に入力されます。この値は、セッションにも保存されます。フォームを送信した後、検証は、フォームから投稿された値がセッションに保存されているかどうかを確認します。そうでない場合、検証は失敗します。テスト中にフォームをレンダリングする必要があることは不可欠です(隠し値を生成してセッションに保存できるようにするため)。その後、レンダリングされたhtmlから隠し値を抽出し、後で隠しハッシュ値を追加できます私たちの要求。次の例を検討してください。
function testAddPageStoreValidData()
{
// render the page with form
$this->dispatch('/form-page');
// fetch content of the page
$html = $this->getResponse()->getBody();
// parse page content, find the hash value prefilled to the hidden element
$dom = new Zend_Dom_Query($html);
$csrf = $dom->query('#csrf')->current()->getAttribute('value');
// reset tester for one more request
$this->resetRequest()
->resetResponse();
// now include $csrf value parsed from form, to the next request
$this->request->setMethod('POST')
->setPost(array('title'=>'MyNewTitle',
'body'=>'Body',
'csrf'=>$csrf));
$this->dispatch('/form-page');
// ...
}
正しいハッシュがセッションに保存され、ハッシュフォーム要素にはハッシュの名前空間を含むZend_Session_Namespaceインスタンスがあります。
要素を単体テストするには、要素内のZend_Session_Namespaceインスタンス(setSessionを使用)を、正しいハッシュを含む自分で作成したインスタンスに置き換えます(ハッシュはキー "hash"に格納されます)
さらなる例については、おそらくZend_Form_Element_HashクラスのZendFramework単体テストを見ることができます。彼らもこれに対処しなければならなかったと思います。
これに似た最近の質問に答えました。将来誰かに役立つ場合に備えて、ここにも私の答えを入れています。
最近、ハッシュ要素を含むフォームをテストする優れた方法を見つけました。これはモック オブジェクトを使用してハッシュ要素をスタブ化するため、心配する必要はありません。この方法で session_start などを行う必要さえありません。フォームを「事前レンダリング」する必要もありません。
最初に「スタブ」クラスを作成します
class My_Form_Element_HashStub extends Zend_Form_Element_Hash
{
public function __construct(){}
}
次に、以下をフォームのどこかに追加します。
class MyForm extends Zend_Form
{
protected $_hashElement;
public function setHashElement( Zend_Form_Hash_Element $hash )
{
$this->_hashElement = $hash;
return $this;
}
protected function _getHashElement( $name = 'hashElement' )
{
if( !isset( $this->_hashElement )
{
if( isset( $name ) )
{
$element = new Zend_Form_Element_Hash( $name,
array( 'id' => $name ) );
}
else
{
$element = new Zend_Form_Element_Hash( 'hashElement',
array( 'id' => 'hashElement' ) );
}
$this->setHashElement( $element );
return $this->_hashElement;
}
}
/**
* In your init method you can now add the hash element like below
*/
public function init()
{
//other code
$this->addElement( $this->_getHashElement( 'myotherhashelementname' );
//other code
}
}
set メソッドは、実際にはテスト目的のためだけにあります。おそらく実際の使用ではまったく使用しないでしょうが、phpunit では次のように修正できます。
class My_Form_LoginTest extends PHPUnit_Framework_TestCase
{
/**
*
* @var My_Form_Login
*/
protected $_form;
/**
*
* @var PHPUnit_Framework_MockObject_MockObject
*/
protected $_hash;
public function setUp()
{
parent::setUp();
$this->_hash = $this->getMock( 'My_Form_Element_HashStub' );
$this->_form = new My_Form_Login( array(
'action' => '/',
'hashElement' => $this->_hash
}
public function testTrue()
{
//The hash element will now always validate to true
$this->_hash
->expects( $this->any() )
->method( 'isValid' )
->will( $this->returnValue( true ) );
//OR if you need it to validate to false
$this->_hash
->expects( $this->any() )
->method( 'isValid' )
->will( $this->returnValue( true ) );
}
}
独自のスタブを作成する必要があります。getMockObject()
ハッシュ要素を直接拡張し、通常のハッシュ要素がそのコンストラクターで「悪」を行うため、phpunit メソッドを呼び出すことはできません。
この方法を使用すると、フォームをテストするためにデータベースに接続する必要さえありません! これを考えるのにしばらく時間がかかりました。
setHashElement()
必要に応じて、メソッドを (変数と get メソッドと共に) FormAbstract 基本クラスにプッシュできます。
覚えておいてください、phpunit では、フォームの構築中にハッシュ要素を渡す必要があります。そうしないinit()
と、set メソッドでスタブ ハッシュを設定する前にメソッドが呼び出され、通常のハッシュ要素を使用することになります。データベースに接続していない場合、セッション エラーが発生する可能性があるため、通常のハッシュ要素を使用していることがわかります。
これが役に立った、または使用している場合はお知らせください。
ZF2 の解決策は、テストでフォームを作成し、csrf フォーム要素から値を取得することです。
$form = new \User\Form\SignupForm('create-user');
$data = [
'security' => $form->get('security')->getValue(),
'email' => 'test@test.com',
'password' => '123456',
'repeat-password' => '123456',
];
$this->dispatch('/signup', 'POST', $data);
Apache vhost ファイルに環境変数を設定します。これにより、コードが実行されているサーバー (開発、ステージング、または運用) がコードに通知されます。
vhost ファイルの行は次のとおりです。
SetEnv SITE_ENV "dev"
次に、フォームが適切な環境に反応するようにします。
if($_SERVER['SITE_ENV']!='dev')
{
$form_element->addValidator($csrf_validator);
}
私はこれと同じテクニックを多くのものに使用しています。たとえば、IS dev の場合、すべての送信メールを自分にリダイレクトします。