# 測試應用程序
- [簡介](#introduction)
- [與你的應用程序進行交互](#interacting-with-your-application)
- [與鏈接交互](#interacting-with-links)
- [與表單交互](#interacting-with-forms)
- [測試 JSON APIs](#testing-json-apis)
- [驗證完全匹配的 JSON](#verifying-exact-match)
- [驗證 JSON 的結構匹配](#verifying-structural-match)
- [Sessions 和認證](#sessions-and-authentication)
- [停用中間件](#disabling-middleware)
- [自定義 HTTP 請求](#custom-http-requests)
- [PHPUnit 斷言](#phpunit-assertions)
<a name="introduction"></a>
## 簡介
Laravel 為 HTTP 請求的生成和發送操作、輸出的檢查,甚至表單的填寫都提供了非常流利的 API。舉例來說,你可以看看下面的這個測試用例:
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
/**
* 基本的測試用例。
*
* @return void
*/
public function testBasicExample()
{
$this->visit('/')
->see('Laravel 5')
->dontSee('Rails');
}
}
`visit` 方法會創建一個 `GET` 請求,`see` 方法則斷言在返回的響應中會有指定的文本,`dontSee` 方法斷言在返回的響應中不會有指定的文本。這是 Laravel 所提供的最基本的應用程序測試。
你也可以使用 `visitRoute` 方法來創建一個 `GET` 請求訪問命名路由。
$this->visitRoute('profile');
$this->visitRoute('profile', ['user' => 1]);
<a name="interacting-with-your-application"></a>
## 與你的應用程序進行交互
當然,除了斷言文本是否存在于一個指定的響應中,你還可以做更多的交互。讓我們來看看點擊鏈接及填寫表單的例子:
<a name="interacting-with-links"></a>
### 與鏈接交互
在這個測試中,我們會生成一個請求并「點擊」返回響應中的鏈接,接著斷言我們會停留在指定的 URI 上。舉個例子,假設在響應中有個鏈接,并寫著「About Us」:
<a href="/about-us">About Us</a>
我們可以編寫一個測試來填寫此表單,并檢查結果:
public function testBasicExample()
{
$this->visit('/')
->click('About Us')
->seePageIs('/about-us');
}
你也可以使用 `seeRouteIs` 方法來檢查用戶是否跳轉到了正確的路由:
->seeRouteIs('profile', ['user' => 1]);
<a name="interacting-with-forms"></a>
### 與表單交互
Laravel 還提供了幾種用于測試表單的方法。通過 `type`、`select`、`check`、`attach` 及 `press` 方法讓你與表單的所有輸入框進行交互。舉個例子,設想有一個在應用程序注冊頁面的表單:
<form action="/register" method="POST">
{{ csrf_field() }}
<div>
Name: <input type="text" name="name">
</div>
<div>
<input type="checkbox" value="yes" name="terms"> Accept Terms
</div>
<div>
<input type="submit" value="Register">
</div>
</form>
我們可以編寫一個測試來填寫此表單,并檢查結果:
public function testNewUserRegistration()
{
$this->visit('/register')
->type('Taylor', 'name')
->check('terms')
->press('Register')
->seePageIs('/dashboard');
}
當然,如果你的表單中包含了類似單選框或下拉式菜單的其它輸入框,也可以很輕松的填入這些類型的區域。以下是每個表單的方法操作列表:
方法 | 說明
------------- | -------------
`$this->type($text, $elementName)` | 「輸入(type)」文本在一個指定的區域
`$this->select($value, $elementName)` | 「選擇(select)」一個單選框或下拉式菜單的區域
`$this->check($elementName)` | 「勾選(check)」一個復選框的區域
`$this->uncheck($elementName)` | 「取消勾選(uncheck)」一個復選框的區域
`$this->attach($pathToFile, $elementName)` | 「附加(attach)」一個文件至表單
`$this->press($buttonTextOrElementName)` | 「按下(press)」一個指定文本或名稱的按鈕 text or name.
<a name="file-inputs"></a>
#### 文件上傳
如果你的表單包含 `上傳文件` 的輸入框類型,則可以使用 `attach` 方法來附加文件:
public function testPhotoCanBeUploaded()
{
$this->visit('/upload')
->attach($pathToFile, 'photo')
->press('Upload')
->see('Upload Successful!');
}
<a name="testing-json-apis"></a>
### 測試 JSON APIs
Laravel 也提供了幾個輔助函數來測試 JSON API 及其響應。舉例來說,`get`、`post`、`put`、`patch` 及 `delete` 方法可以用于發出各種 HTTP 動作的請求。你也可以輕松的傳入數據或標頭到這些方法上。首先,讓我們來編寫一個測試,將 `POST` 請求發送至 `/user` ,并斷言其會返回 JSON 格式的指定數組:
<?php
class ExampleTest extends TestCase
{
/**
* 基本的功能測試示例。
*
* @return void
*/
public function testBasicExample()
{
$this->json('POST', '/user', ['name' => 'Sally'])
->seeJson([
'created' => true,
]);
}
}
> {tip} `seeJson` 方法會將傳入的數組轉換成 JSON,并驗證該 JSON 片段是否存在于應用程序返回的 JSON 響應中的 **任何位置**。也就是說,即使有其它的屬性存在于該 JSON 響應中,但是只要指定的片段存在,此測試便會通過。
<a name="verifying-exact-match"></a>
### 驗證完全匹配的 JSON
如果你想驗證傳入的數組是否與應用程序返回的 JSON **完全** 匹配,則可以使用 `seeJsonEquals` 方法:
<?php
class ExampleTest extends TestCase
{
/**
* 基本的功能測試示例。
*
* @return void
*/
public function testBasicExample()
{
$this->json('POST', '/user', ['name' => 'Sally'])
->seeJsonEquals([
'created' => true,
]);
}
}
<a name="verifying-structural-match"></a>
### 驗證 JSON 的結構匹配
你可以使用 `seeJsonStructure` 來驗證 JSON 結構是否符合你的預期:
<?php
class ExampleTest extends TestCase
{
/**
* 基本的功能測試示例。
*
* @return void
*/
public function testBasicExample()
{
$this->get('/user/1')
->seeJsonStructure([
'name',
'pet' => [
'name', 'age'
]
]);
}
}
上面這個例子展示接受到的數據會有一個 `name` 屬性和一個擁有 `name` 和 `age` 屬性的嵌套 `pet` 對象。`seeJsonStructure` 并不會因為響應結果中包含額外的屬性而失敗。比如,即使響應中 `pet` 對象含有一個 `weight` 屬性,測試依舊會通過。
你可以使用 `*` 來假設所有的列表內容都包含至少數組里面的內容:
<?php
class ExampleTest extends TestCase
{
/**
* 基本的功能測試示例。
*
* @return void
*/
public function testBasicExample()
{
// 每一個列表里至少擁有 id, name 和 email 屬性
$this->get('/users')
->seeJsonStructure([
'*' => [
'id', 'name', 'email'
]
]);
}
}
你也可以靈活的使用 `*` 做嵌套。在下面這個實例中,我們可以斷言在響應數據中每個 user 都包含指定的屬性,而且用戶的每個 pet 對象也包含指定的屬性集:
$this->get('/users')
->seeJsonStructure([
'*' => [
'id', 'name', 'email', 'pets' => [
'*' => [
'name', 'age'
]
]
]
]);
<a name="sessions-and-authentication"></a>
### Sessions 和認證
Laravel 提供了幾個可在測試時使用 Session 的輔助函數。首先,你需要設置 Session 數據至指定的數組中,并使用 `withSession` 方法。在應用程序的測試請求發送之前,可先給數據加載 session:
<?php
class ExampleTest extends TestCase
{
public function testApplication()
{
$this->withSession(['foo' => 'bar'])
->visit('/');
}
}
當然,一般使用 Session 時都是用于維持用戶的狀態,如認證用戶。`actingAs` 輔助函數提供了簡單的方式來讓指定的用戶認證為當前的用戶。舉個例子,我們可以使用 [模型工廠](#model-factories) 來生成并認證用戶:
<?php
class ExampleTest extends TestCase
{
public function testApplication()
{
$user = factory(App\User::class)->create();
$this->actingAs($user)
->withSession(['foo' => 'bar'])
->visit('/')
->see('Hello, '.$user->name);
}
}
你也可以使用 `actingAs` 來指定用戶使用哪個 guard:
$this->actingAs($user, 'api')
<a name="disabling-middleware"></a>
### 停用中間件
測試應用程序時,你會發現,在某些測試中停用 [中間件](/docs/{{version}}/middleware) 是很方便的。這讓你可以隔離任何中間件的所有影響,以便更好的測試路由及控制器。Laravel 包含了一個簡潔的 `WithoutMiddleware` trait,你能在測試類中使用它來自動停用所有的中間件:
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
use WithoutMiddleware;
//
}
如果你只想要在某幾個測試方法中停用中間件,則可以在測試方法中調用 `withoutMiddleware` 方法:
<?php
class ExampleTest extends TestCase
{
/**
* 基本的功能測試示例。
*
* @return void
*/
public function testBasicExample()
{
$this->withoutMiddleware();
$this->visit('/')
->see('Laravel 5');
}
}
<a name="custom-http-requests"></a>
### 自定義 HTTP 請求
如果你想要創建一個自定義的 HTTP 請求到應用程序上,并獲取完整的 `Illuminate\Http\Response` 對象,則可以使用 `call` 方法:
public function testApplication()
{
$response = $this->call('GET', '/');
$this->assertEquals(200, $response->status());
}
如果你創建的是 `POST`、`PUT`、或是 `PATCH` 請求,則可以在請求時傳入一個數組作為輸入數據。當然,你也可以在路由及控制器中通過 [請求實例](/docs/{{version}}/requests) 取用這些數據:
$response = $this->call('POST', '/user', ['name' => 'Taylor']);
<a name="phpunit-assertions"></a>
### PHPUnit 斷言
方法 | 描述
------------- | -------------
`->assertResponseOk();` | 斷言客戶端的響應擁有 OK 狀態碼。
`->assertResponseStatus($code);` | 斷言客戶端的響應擁有指定的狀態碼。
`->assertViewHas($key, $value = null);` | 斷言響應視圖擁有指定的部分綁定數據。
`->assertViewHasAll(array $bindings);` | 斷言響應視圖里存在傳參數組里的所有數據
`->assertViewMissing($key);` | 斷言響應視圖擁有指定的綁定數據列表。
`->assertRedirectedTo($uri, $with = []);` | 斷言客戶端是否被重定向至指定的 URI。
`->assertRedirectedToRoute($name, $parameters = [], $with = []);` | 斷言客戶端是否被重定向到指定的路由。
`->assertRedirectedToAction($name, $parameters = [], $with = []);` | 斷言客戶端是否被重定向到指定的行為。
`->assertSessionHas($key, $value = null);` | 斷言 session 中有指定的值。
`->assertSessionHasAll(array $bindings);` | 斷言 session 中有指定的列表值。
`->assertSessionHasErrors($bindings = [], $format = null);` | 斷言 session 有錯誤的綁定。
`->assertHasOldInput();` | 斷言 session 有舊的輸入數據。
`->assertSessionMissing($key);` | 斷言 session 中沒有指定的值。
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
|---|---|---|---|
| [@JobsLong](https://phphub.org/users/56) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/56_1427370654.jpeg?imageView2/1/w/100/h/100"> | 翻譯 | 我的個人主頁:[http://jobslong.com](http://jobslong.com) |
- 說明
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- 錯誤與日志
- 開發環境
- HomeStead
- Valet
- 核心概念
- 服務容器
- 服務提供者
- 門面(facades)
- contracts
- HTTP層
- 路由
- 中間件
- CSRF保護
- 控制器
- 請求
- 響應
- Session
- 表單驗證
- 視圖與模板
- 視圖
- Blade模板
- 本地化
- Javascript與CSS
- 入門指南
- laravel-elixir
- 安全
- 用戶認證
- 用戶授權
- 重置密碼
- API授權
- 加密解密
- 哈希
- 綜合話題
- 廣播系統
- 緩存系統
- 事件系統
- 文件存儲
- 郵件發送
- 消息通知
- 隊列
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent集合
- 修改器
- 序列化
- Artisan控制臺
- Artisan 命令行
- 任務調度
- 測試
- 快速入門
- 應用程序測試
- 數據庫測試
- 模擬器
- 官方擴展包
- Cashier交易包
- Envoy 部署工具
- Passport OAuth 認證
- Scout 全文搜索
- Socialite 社交化登錄
- 附錄
- 集合
- 輔助函數
- 擴展包開發
- 交流說明