我正在使用CSRF隱藏哈希元素與Zend_Form,並試圖單元測試登錄,但不知道如何編寫單元測試,以包括該元素。在文檔中查找並閱讀儘可能多的教程。我甚至delicioused them all,但沒有人提到這一點。你如何測試一個包含CSRF表單元素的Zend_Form?
回答
正確的散列存儲在會話中,並且散列表單元素具有包含散列名稱空間的Zend_Session_Namespace實例。
進行單元測試的元素,你將與一個替代的Zend_Session_Namespace實例中的元素(setSession)您自己創建其中包含正確的散列(哈希存儲在關鍵的「哈希」)
爲了進一步你可以看看Zend Framework的單元測試Zend_Form_Element_Hash類的例子。我想他們也必須處理這個問題。
我覺得有什麼問題,當你必須知道這麼多關於實施CSRF爲使用它的控制器編寫測試。 – 2011-10-24 01:31:51
在更復雜的情況下,您可能會用模擬實例替換整個CSRF表單元素,那麼您將不需要處理會話存儲的東西 – 2011-10-24 08:01:02
我在我的Apache虛擬主機文件,它告訴哪個服務器運行它的代碼設置環境變量: 開發,分期或生產
的虛擬主機文件中的行是:
SetEnv SITE_ENV "dev"
然後,我只是讓我的形式作出反應,適當的環境:
if($_SERVER['SITE_ENV']!='dev')
{
$form_element->addValidator($csrf_validator);
}
我用的東西很多相同的技術。例如,如果它是開發者,我將所有外發電子郵件重定向到我等。
這與我在forms.ini文件中做的事情類似... 我不知道爲什麼但不是IF語句的粉絲在腳手架或.ini文件之外,用於主代碼內部的環境特定處理。看起來像一個新的環境將需要尋找在很多地方修復它,而不是.ini和bootstrap在你期望的差異.... – joedevon 2009-07-13 04:58:04
每次渲染表單時都會生成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');
// ...
}
我回答類似這樣的一個較新的問題。我也會在這裏提供我的答案,以便將來幫助任何人。
我最近發現了一個用哈希元素測試表單的好方法。這將使用一個模擬對象來存儲哈希元素,你不必擔心它。你甚至不需要這樣做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
}
}
設置方法只是爲了測試的目的。在實際使用中,您可能根本不會使用它,但現在在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);
- 1. 單元測試自定義Zend_Form元素
- 2. 如何填充()整個Zend_Form減去一個表單元素?
- 3. 如何測試數組是否至少包含一個元素
- 4. 單元測試包含多個提交按鈕的Django表單
- 5. 共享一個包含多個項目的單元測試
- 6. 包含一個元素的jaxb列表
- 7. 單元測試一個包含HttpContext的靜態類的調用
- 8. 單元測試一個包含ngbTypeahead的組件
- 9. 發佈一個python包 - 你應該包含doc和測試嗎?
- 10. 你如何使用測試單元?
- 11. 你如何加快Java單元測試?
- 12. 你如何單元測試HTML.ActionLink
- 13. 書寫單元測試表單元素
- 14. 你會如何單元測試一個內存分配器?
- 15. 如何測試Zend_Form類?
- 16. 如何測試一個表單對象包含一個Form屬性?
- 17. 如何匹配包含另一個元素的元素?
- 18. 帶WebRequest的Spring Boot單元測試,包含表單提交
- 19. 如何測試CSRF
- 20. 是否包含運行單元測試?
- 21. 單元測試包含一個無限循環
- 22. 你如何測試oauth的單元測試控制器?
- 23. 你用單元測試測試什麼?
- 24. 使用CSRF進行單元測試ZF2表單的問題
- 25. 瓶禁用CSRF在單元測試
- 26. Spring Boot,Freemarker,MVC單元測試,Csrf
- 27. 找到包含元素的表單?
- 28. zend_form - 如何獲取除禁用元素以外的表單值
- 29. 如何測試矢量是否包含重複元素?
- 30. 如何測試Excel中的Range是否包含單元格?
更新:這是一個有點缺憾,但我能得到一個可測試的形式,因爲我裝我的Zend_Form來自.ini文件。我將csrf部分分解爲僅測試部分,這樣我的測試就可以在不通過csrf的情況下進行登錄。希望這可以幫助別人。順便說一句,我認爲一個.ini文件是加載你的表格的最佳地方。 – joedevon 2009-07-11 00:07:36
PHPUnit的創建者向我提到「端到端測試!=單元測試」,這當然是事實。在這種情況下,我並不在乎如何獲取csrf,因爲我想測試我可以登錄並在結果頁面上看到某個元素。不能在測試中包含此元素正在殺死登錄... – joedevon 2009-07-12 05:43:03