天天看點

Symfony2Book08:測試

無論何時,你隻要編寫一行新的代碼,你就有可能引入新的Bug。你應該使用自動測試,該教程将向你顯示如何為你的應用程式編寫單元測試和功能測試。

Symfony2測試很大程式上依賴PHPUnit,它的最佳實踐,和一些約定。這部分并不是PHPUnit本身的文檔,但如果你還是不能了解的話,你可以閱讀它優秀的文檔 。

Symfony2使用PHPUnit 3.5.11或以上版本。

預設的PHPUnit配置将在你Bundle的Tests/子目錄中查找測試:

對指定應用程式運作測試套件是簡單的:

代碼的覆寫範圍可以通過 --coverate-html 來生成。

編寫Symfony2單元測試與标準PHPUnit的單元測試沒什麼不同。通常推薦将Bundle目錄結構複制到Tests/子目錄中。是以為Acme\HelloBundle\Model\Article類所寫的測試會放置在Acme/HelloBundle/Tests/Model/ArticleTest.php檔案中。

在單元測試中,自動加載通過src/autoload.php檔案是自動啟用的(這在phpunit.xml.dist檔案中是被預設配置的)。

為指定檔案或目錄運作測試也十分容易:

功能測試檢查應用程式不同層的內建(從路由到視圖)。就PHPUnit關注度而言,它們與單元測試沒什麼不同,除了它們有一個非常特殊的工作流:

*制作一個請求

*測試響應

*點選連結或送出表單

*修正和重複

請求、點選和送出通過一個知道如何與應用程式通信用戶端來實作。要通路該用戶端,你的測試必須繼承Symfony2的WebTestCase類。沙箱提供了一個HelloControoler控制器簡單的功能測試,如下所示:

createClient()方法傳回一個與目前應用程式綁定的用戶端

request()方法傳回一個Crawler對象,該對象可以用于在Response中選擇元素。可以用來點選連結,也可以用來送出表單。

當Response的内容是XML或HTML文檔,可以隻使用Crawler對象。對于内容的其它類型,可以通過$client->getResponse()->getContent()來得到内容。

點選連結:首先選擇Crawler使用XPath表達式或CSS選擇器的連結,然後用Client去點選它:

送出表單也非常簡單;選擇一個表單按鈕,你可以覆寫一些表單的值,然後送出相應的表單:

每個表單項根據它的類型都有相對應的方法:

如果不想一次改變一個表單項,你也可以發送一個數組給submit()方法:

現在你可以很輕易浏覽應用程式,使用聲明去測試看看程式實際上是否按你所預期的執行。使用Crawler在DOM上執行中斷:

或者,如果你隻是想聲明内容包含一些文本,test可以直接針對Response内容。如果Response不是一個XML/HTML文檔,則無法實作。(這段翻得不暢,留下英文原文吧)

Or, test against the Response content directly if you just want to assert that the content contains some text, or if the Response is not an XML/HTML document:

在一段時間之後,你會注意到你總是寫同一類型的聲明。為了你更快地開始,這裡有一個常用的聲明清單:

測試用戶端模拟類似浏覽器的HTTP用戶端。

測試用戶端基于BrowserKit和Crawler元件。

用戶端知道如何制作一個發往Symfony2應用的請求:

request()方法将HTTP方法和URL作為參數,然後傳回一個Crawler實體。

使用Crawler去發現Response中的DOM元素。這些元素随後可以用于點選連結和送出表單:

click()和submit()方法都傳回一個Crawler對象。這些方法浏覽應用程式并隐藏大量細節的最好方式。例如,當你送出一個表單時,它自動比對HTTP方法和表單URL、它給你一個設計良好的API去上傳檔案、它合并表單預設值和送出值,等等儲如此類。

在接下來的Crawler章節中,你将學到更多關于Link和Form對象。

但你也可以使用request()方法的附加參數來模拟表單送出和複雜請求:

當一個請求傳回一個重定向響應,用戶端會自動遵循它。這個行為可以被followRedirects()方法改變:

當用戶端遵循響應進行重定向時,你可以使用followRedirect()迫強使它進行重定向:

最後但并非不重要,當在同一腳本使用多個用戶端工作時,你可以迫使每個請求都在它自己的PHP程序中執行以避免産生副作用。

用戶端支援許多實際浏覽器的操作

如果你使用用戶端去測試你的應用程式,你也許想去通路用戶端的内部對象:

你也可以得到最後請求相應的對象:

如果你的請求沒有被隔離,你也可以通路Container和Kernel:

強烈建議功能測試隻測試Response。但在幾種非常罕見的情況下,你也許想要通路一些内部對象對編寫聲明。在這種情況下,你可以通路依賴注入容器:

警告:如果你隔離了用戶端或使用HTTP層,它将不能工作。

如果你所需資訊被分析器檢出是可用的話,那麼用它們代替。

要讓聲明資料被分析器收集,你可以所下所示得到分析器:

預設狀态下,用戶端遵循HTTP重定向。但如果你想在重定向之前得到Response并将其重定向給自己,那麼調用followRedirects()方法:

每次你用Client生成請求時都會傳回一個Crawler執行個體。它允許你周遊HTML文檔、選擇節點、找到連結和表單。

當你用Client生成請求時,一個Crawler執行個體将會自動為你建立。但你也可以很容易地自行建立:

構造函數有兩個參數:第2個參數是為連結和表單生成絕對URL的URL;第1個參數可以使用以下内容:

* HTML文檔

* XML文檔

* DOMDocument執行個體

* DOMNodeList執行個體

* 上述元素的數組

建立之後,你可以添加更多的節點:

方法

描述

addHTMLDocument()

HTML文檔

addXMLDocument()

XML文檔

addDOMDocument()

DOMDocument執行個體

addDOMNodeList()

DOMNodeList執行個體

addDOMNode()

DOMNode執行個體

addNodes()

上述元素的數組

add()

接受上述任一進制素

象jQuery一樣,Crawler有方法去周遊HTML/XML文檔的DOM:

filter('h1')

比對CSS選擇器的節點

filterXpath('h1')

比對XPath表達式的節點

eq(1)

指定索引的節點

first()

第1個節點

last()

最後1個節點

siblings()

兄弟節點

nextAll()

所有後面的兄弟節點

previousAll()

所有前面的兄弟節點

parents()

父節點

children()

子節點

reduce($lambda)

所有被調用後不傳回false的節點

你可以通過鍊式方法調用來疊代縮小你選擇的節點,注意你每個比對節點用的方法都需要傳回一個新的Crawler執行個體。

使用count()函數得到儲存在Crawler:count($crawler)中的節點數。

Crawler可以從節點提取資訊:

你可以選擇帶有周遊方法的連結,但selectLink()快捷方法更為友善:

它選擇包含指定文本的連結,或者alt屬性包含指定文本的可點選圖檔。

Client對象的click()方法驅動一個被link()方法傳回的Link執行個體:

links()方法為所有節點傳回一個Link對象的數組。

你選擇有着selectButton()方法的表單:

注意我們選擇了表單按鈕而不是表單,因為表單可以有幾個按鈕;如果你使用周遊API,那麼注意你必須發現按鈕。

selectButton()方法可以選擇按鈕标簽并送出input标簽;這兒有一些發現它們的技巧:

* 值,屬性的值

* 圖檔的id或alt屬性

* 按鈕标簽的id或name屬性

當你有一個代表按鈕的節點,調用form()方法去得到一個Form執行個體,因為表單包含按鈕節點:

當調用form()方法時,你也可以發送一個覆寫預設值的那些表單項值的數組:

如果你想為表單模拟一個特定的HTTP方法,将其作為第2個參數:

Client可以送出一個Form執行個體:

表單項的值也可以作為submit()方法的第2個參數發送:

更複雜的情況,使用Form執行個體,并用一個數組來設定每個單獨表單項的值:

也有設計良好的API按照表單項的類型去操作它的值:

你可以通過調用getValues()方法得到将送出的值。被上傳的檔案也可以通過getFiles()傳回的數組中得到。getPhpValues()和getPhpFiles()也傳回被送出的值,但是以PHP格式傳回的(它将方括号中的關鍵詞轉換成PHP數組)。

每個應用程式都有它自己的PHPUnit配置,它們被儲存在phpunit.xml.dist檔案中。你可以編輯這個檔案以改變預設值或者建立phpnit.xml檔案去為你的本地機調整配置。

在你的代碼庫中儲存phpunit.xml.dist檔案,并忽略phpunit.xml檔案。

預設情況下,測試隻被儲存在那些通過運作phpunit指令的“标準”Bundle中,(标準是指測試位于Vendor\*Bundle\Tests名稱空間)。但你可以很友善地添加更多的名稱空間。例如,下面的配置将測試添加在安裝的第三方Bundle中。

為了包含代碼範圍中的其它名稱空間,也可以編輯<filter>段:

通過功能測試使用的Client建立一個在特定測試環境下運作的Kernel,是以你可以如你所願地調整它:

你也可以改變預設環境(test),通過覆寫調試模式(true),并将其做為選項發送給createClient()方法:

如果你的應用程式是根據一些HTTP頭來運作的話,那麼将它們作為第2個參數發送給createClient():

你也可以覆寫每個請求的HTTP頭。

覆寫test.client.class參數或定義一個test.client服務來提供你自己的Client。

本文轉自 firehare 51CTO部落格,原文連結:http://blog.51cto.com/firehare/586500,如需轉載請自行聯系原作者