## **簡介**
PHPUnit 作為一個 PHP 測試框架功能很強大,但是只能用于測試后端接口和功能,無法模擬瀏覽器端行為測試基于 JavaScript 的前端應用。
為此,Laravel為瀏覽器測試提供了一個官方擴展包——Laravel Dusk(該特性是在Laravel 5.4引入的),它基于[ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/home)(一個 Selenium WebDriver,支持桌面版和移動版 Chrome 瀏覽器)和[Facebook php-webdriver](https://github.com/facebook/php-webdriver)(Selenium WebDriver PHP 客戶端)構建,我們可以通過它來模擬在瀏覽器中的任何操作,從而實現瀏覽器自動化測試的目的。
Laravel Dusk 為我們做好了底層封裝,你不需要單獨安裝 Selenium,也不需要有之前使用過 Selenium 的經驗,就可以通過 Dusk 提供的方法輕松上手瀏覽器自動化測試。下面我們就來簡單介紹如何在 Laravel 項目中基于 Dusk 實現瀏覽器自動化測試。
> 注:Selenium 是一組工具集,用于實現測試自動化,關于 Selenium 的更多細節請參考[官方文檔](https://www.seleniumhq.org/),或者閱讀相應的[中文文檔](http://www.hmoore.net/wizardforcel/selenium-doc/102082)。
## **安裝配置**
首先,在 Laravel 項目根目錄下通過 Composer 安裝 Dusk 擴展包:
~~~
composer require --dev laravel/dusk
~~~
我們只在本地開發環境或測試環境安裝 Dusk,所以加上了`--dev`選項,如果在生產環境安裝,存在安全風險,例如可以以任何用戶的身份登錄到應用,所以不建議在生產環境使用。
接下來,運行 Artisan 命令`dusk:install`執行初始化操作:
~~~
php artisan dusk:install
~~~
該命令會在`tests`目錄下創建一個`Browser`目錄并包含一個測試用例示例:

從根源上看,瀏覽器測試用例也是繼承自`PHPUnit\Framework\TestCase`,所以可以在用例中使用前面提到的所有 PHPUnit 及 Laravel 框架提供的斷言方法。
你可能已經注意到生成的子目錄中還包含了一個`screenshots`目錄,當測試失敗時,Dusk 會將屏幕截屏并將圖片保存到該目錄,這在調試時很有幫助。
接下來,需要更新`.env`文件中的`APP_URL`配置項,這里配置為項目的虛擬域名即可,比如`http://laravel58.test`,該域名需要和 Web 服務器中的配置保持一致,以便可以通過瀏覽器訪問。
> 注:除此之外,你還可以讓 Dusk 選擇使用自己獨立的環境配置文件,例如`.env.dusk.local`,如果是測試環境,則對應的配置文件是`.env.dusk.testing`。
## **運行測試**
做好以上初始化工作后,就可以在項目根目錄下通過如下 Artisan 命令基于 Dusk 運行瀏覽器測試了:
~~~
php artisan dusk
~~~
該命令會運行`tests\Browser\ExampleTest.php`文件中的`ExampleTest`:
~~~
class ExampleTest extends DuskTestCase
{
/**
* A basic browser test example.
*
* @return void
*/
public function testBasicExample()
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertSee('Laravel');
});
}
}
~~~
其中,我們向`browse`方法傳入了一個包含`Browser`實例的回調,在該回調中,我們可以基于`Browser`實例提供的方法模擬瀏覽器的各種操作,然后通過斷言方法對結果進行測試。比如這里通過`visit`方法模擬在瀏覽器中訪問`http://laravel58.test/`URL,然后通過`assertSee`方法斷言結果頁面是否包含`Laravel`字符串。
如果測試失敗,就會在`tests/Browser/screenshots`目錄下生成一張測試失敗時的頁面截圖。
看完這個最基本的測試用例,下面我們來看一些稍微復雜一點的例子。
## **表單和認證**
通過 Dusk 還可以與表單進行交互,下面我們基于 Laravel[認證腳手架代碼](https://xueyuanjun.com/post/19484.html#toc_2)模擬表單交互來測試用戶認證功能。
完整認證腳手架代碼生成和數據庫遷移后,我們通過如下 Artisan 命令創建一個新的瀏覽器測試用例`RegisterTest`:
~~~
php artisan dusk:make RegisterTest
~~~
該命令會在`tests/Browser`目錄下生成`RegisterTest.php`文件,我們修改`testExample`方法如下:
~~~
/**
* A Dusk register test example.
*
* @return void
*/
public function testExample()
{
$this->browse(function (Browser $browser) {
$browser->visit('/') // 訪問首頁
->clickLink('Register') // 點擊注冊按鈕
->assertSee('Register') // 斷言注冊頁面包含Register文本
// 通過下面這些值填充注冊表單
->value('#name', 'test_01')
->value('#email', 'test_01@laravel58.test')
->value('#password', 'test123456')
->value('#password-confirm', 'test123456')
->click('button[type="submit"]') // 點擊注冊按鈕
->assertPathIs('/home') // 注冊成功后跳轉到 /home 頁面
->assertSee("You are logged in!"); // 登錄成功后提示文本
});
}
~~~
在這段測試用例中,我們首先訪問應用首頁,然后通過`clickLink`方法模擬點擊注冊鏈接,進入注冊頁面后,先斷言頁面是否包含「Register」文本,然后通過`value`方法填充表單,在該方法中,第一個參數是 CSS 選擇器,第二個是對應輸入框的值,表單填充完畢后,通過`click`方法模擬點擊注冊按鈕提交表單,提交表單注冊成功后,斷言頁面是否跳轉到`/home`路由,并斷言登錄成功提示文本是否出現,至此,我們就編寫好了注冊流程的自動化測試。
顯然,相比于通過 Laravel 功能測試編寫的測試用例,瀏覽器測試功能更加強大,更具有整體性,因為功能測試只能模擬測試指定的后端路由,而瀏覽器測試可以模擬完整的用戶操作流程,能夠在一個用例中測試一個完整的事務。
編寫好瀏覽器測試代碼后,再次運行測試用例:
~~~
php artisan dusk
~~~
測試通過,此時查看數據庫,會發現`users`表中新增了一個名為`test_01`的測試用戶。
你可以模仿注冊流程測試下用戶登錄流程,除此之外,Dusk 還支持很多與其他頁面元素的交互以及額外封裝的斷言方法,具體可以參考[官方文檔](https://xueyuanjun.com/post/19543.html)。