Използвам CSRF скрития хеш елемент със Zend_Form и се опитвам да тествам единица за влизане, но не знам как да напиша Unit Test, за да включа този елемент. Погледнах в документите и прочетох колкото се може повече уроци, които можах да намеря. Дори вкусих всички, но никой не споменава това.
Как тествате единица Zend_Form, която включва елемента CSRF форма?
Отговори (5)
Правилният хеш се съхранява в сесията и елементът на формуляра Hash има екземпляр Zend_Session_Namespace, който съдържа пространството от имена за хеша.
За да тествате елемента, трябва да замените екземпляра Zend_Session_Namespace в елемента (със setSession) с такъв, който създавате сами и който съдържа правилния хеш (хешът се съхранява в ключ "hash")
За допълнителни примери вероятно бихте могли да разгледате модулните тестове на Zend Framework за класа Zend_Form_Element_Hash. Предполагам, че е трябвало да се справят и с това.
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');
// ...
}
$html = $this->getResponse()->getBody();
винаги е празно в моя случай.
- person takeshin; 03.02.2011
$form = new MyForm(); $form->render();
вместо да изпращате страницата два пъти. Определено е по-бързо.
- person fracz; 30.05.2014
Зададох променлива на средата в моя vhost файл на Apache, която казва на кода на кой сървър се изпълнява: разработка, етап или производство
Редът за vhost файла е:
SetEnv SITE_ENV "dev"
Тогава просто карам формулярите си да реагират на подходящата среда:
if($_SERVER['SITE_ENV']!='dev')
{
$form_element->addValidator($csrf_validator);
}
Използвам същата техника за много неща. Например, ако IS dev, пренасочвам всички изходящи имейли към мен и т.н.
Отговорих на по-скорошен въпрос, подобен на този. Поставям отговора си тук, в случай че ще помогне на някого в бъдеще.
Наскоро намерих страхотен начин за тестване на формуляри с хеш елементи. Това ще използва фиктивен обект, за да премахне хеш елемента и няма да се налага да се притеснявате за това. Дори няма да се налага да правите session_start или нещо подобно по този начин. Няма да се налага и да „предварително изобразявате“ формуляра.
Първо създайте клас "stub" така
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
}
}
Зададеният метод наистина е там само за целите на тестването. Вероятно изобщо няма да го използвате по време на реална употреба, но сега в 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 ) );
}
}
ТРЯБВА да създадете свой собствен мъниче. Не можете просто да извикате метода phpunit getMockObject()
, защото това директно ще разшири хеш елемента, а нормалният хеш елемент прави „зли“ неща в своя конструктор.
С този метод дори не е необходимо да сте свързани към база данни, за да тествате формулярите си! Отне ми известно време да мисля за това.
Ако желаете, можете да натиснете метода setHashElement()
(заедно с променливата и метода get) в някой базов клас FormAbstract.
ЗАПОМНЕТЕ, че в phpunit ТРЯБВА да предадете хеш елемента по време на конструирането на формуляр. Ако не го направите, вашият init()
метод ще бъде извикан, преди хешът ви да може да бъде зададен с метода set и в крайна сметка ще използвате обикновения хеш елемент. Ще знаете, че използвате обикновен хеш елемент, защото вероятно ще получите някаква грешка в сесията, ако НЕ сте свързани към база данни.
Кажете ми, ако намирате това за полезно или ако го използвате.
Решението за ZF2 е създаване на вашия формуляр в тест и получаване на стойност от вашия csrf елемент на формуляр:
$form = new \User\Form\SignupForm('create-user');
$data = [
'security' => $form->get('security')->getValue(),
'email' => '[email protected]',
'password' => '123456',
'repeat-password' => '123456',
];
$this->dispatch('/signup', 'POST', $data);