* * * * *
[TOC]
## 簡介
Laravel提供了各種有用的工具,以便更容易地測試數據庫驅動的應用程序。 首先, 你可以使用?`assertDatabaseHas`輔助函數, 來斷言數據庫中是否存在與指定條件互相匹配的數據。 例如,如果我們想驗證?`users`?數據表中是否存在?`email`?值為?`sally@example.com`的數據, 你可以按照以下方式來測試:
~~~
public function testDatabase()
{
// 創建調用至應用程序...
$this->assertDatabaseHas('users', [
'email' => 'sally@example.com'
]);
}
~~~
你也可以使用?`assertDatabaseMissing`?輔助函數來斷言數據不在此數據庫中。
當然,使用?`assertDatabaseHas`?方法和其它輔助函數只是為了方便。 你也可以隨意使用PHPUnit內置的斷言方法來擴充測試。
## 生成模型工廠
創建一個模型工廠, 使用 Artisan 命令?`make:factory`?來快速創建模型工廠:
~~~
php artisan make:factory PostFactory
~~~
這個新的模型工廠將被放置在?`database/factories`?目錄中。
`--model`?選項可用于指定當模型工廠被創建時生成模型的名稱。這個選項將用給定的模型預填充生成的模型工廠文件 :
~~~
php artisan make:factory PostFactory --model=Post
~~~
## 每次測試后重置數據庫
每次測試后重置數據庫是很有用的,這樣以前測試的數據不會干擾后續的測試。?`RefreshDatabase`?trait 會采用最優的方法來遷移你的數據庫,這取決于你使用的是內存數據庫還是傳統數據庫。在你的測試類引用這個trait,一切將為你處理:
~~~
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
use RefreshDatabase;
/**
* 一個基本功能測試示例
*
* @return void
*/
public function testBasicExample()
{
$response = $this->get('/');
// ...
}
}
~~~
## 創建模型工廠
測試時,在運行測試之前常常需要插入一些數據到數據庫中。當你創建測試數據時,除了手動設置每個字段的值,Laravel還可以使用?[Eloquent模型](http://www.hmoore.net/tonyyu/laravel_5_6/786272)的工廠來設置每個屬性的默認值。在開始之前, 你可以先看一下應用程序?`database/factories/UserFactory.php`?的文件。 開箱即用,這個文件包含一個模型工廠定義:
~~~
use Faker\Generator as Faker;
$factory->define(App\User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
'remember_token' => str_random(10),
];
});
~~~
在這個模型工廠定義的閉包中,你可以返回模型上所有屬性的默認測試值。閉包將接受 PHP 函數庫?[Faker](https://github.com/fzaninotto/Faker)?的一個實例,它允許你便捷的生成各種隨機數據來進行測試。
你也可以為每個模型創建一個工廠文件以實現更好的組織。 例如,你可以自`database/factories`?目錄下創建?`UserFactory.php`?和`CommentFactory.php`?文件。 Laravel將自動加載?`factories`?目錄下的所有文件。
> {tip} 你也可以在?`config/app.php`?配置文件中添加?`faker_locale`?選項來設置 Faker 的語言環境。
### 工廠狀態
工廠狀態可以讓你任意組合你的模型工廠,僅需要做出適當差異化的修改,就可以達到讓模型擁有多種不同的狀態。例如, 你的?`User`?模型中可以修改某個默認屬性值來達到標識一種?`delinquent`?狀態。你可以使用?`state`?方法來進行這種狀態轉換。對于簡單的工廠狀態,你可以傳入要修改的屬性數組:
~~~
$factory->state(App\User::class, 'delinquent', [
'account_status' => 'delinquent',
]);
~~~
如果你的工廠狀態需要計算或者使用?`$faker`?實例。你可以使用閉包方法來實現狀態屬性的修改:
~~~
$factory->state(App\User::class, 'address', function ($faker) {
return [
'address' => $faker->address,
];
});
~~~
## 使用模型工廠
### 創建模型
模型工廠定義后,就可以在測試或者是數據庫的填充文件中,通過全局的?`factory`?函數來生成模型實例。因此,先讓我們來看看幾個模型創建的例子。 首先,我們將使用?`make`?方法創建模型但不將他們保存至數據庫:
~~~
public function testDatabase()
{
$user = factory(App\User::class)->make();
// 在測試中使用模型...
}
~~~
你也可以創建一個含有多個模型的集合,或創建一個指定類型的模型:
~~~
// 創建三個 App\User 實例...
$users = factory(App\User::class, 3)->make();
~~~
#### 應用模型工廠狀態
你可能需要在你的模型中應用不同的?[模型工廠狀態](http://www.hmoore.net/tonyyu/laravel_5_6/786284#_91)?。 如果你想模型加上多種不同的狀態,你只需指定每個你想要添加狀態的名稱就可以了:
~~~
$users = factory(App\User::class, 5)->states('delinquent')->make();
$users = factory(App\User::class, 5)->states('premium', 'delinquent')->make();
~~~
### 使用回調
你可以使用?`afterMaking`?和?`afterCreating`?兩個方法來注冊模型工廠回調。示例代碼如下:
~~~
$factory->afterMaking(App\User::class, function ($user, $faker) {
// ...
});
$factory->afterCreating(App\User::class, function ($user, $faker) {
$user->accounts()->save(factory(App\Account::class)->make());
});
~~~
你可以可以為?[模型工廠狀態](http://www.hmoore.net/tonyyu/laravel_5_6/786284#_91)?定義回調:
~~~
$factory->afterMakingState(App\User::class, 'delinquent', function ($user, $faker) {
// ...
});
$factory->afterCreatingState(App\User::class, 'delinquent', function ($user, $faker) {
// ...
});
~~~
#### 重寫模型屬性
通過給?`make`?方法傳入一個數組,可以重寫模型的默認屬性值。這樣僅替換指定的屬性,其他的屬性還是由模型工廠默認填充:
~~~
$user = factory(App\User::class)->make([
'name' => 'Abigail',
]);
~~~
### 模型持久化
`create`?方法創建模型實例的同時還調用了把記錄寫入數據庫的?`save`?方法:
~~~
public function testDatabase()
{
// 創建單個 App\User 實例
$user = factory(App\User::class)->create();
// 創建三個 App\User 實例
$users = factory(App\User::class, 3)->create();
// 在測試中使用模型
}
~~~
傳一個數組給?`create`?方法重寫模型的屬性:
~~~
$user = factory(App\User::class)->create([
'name' => 'Abigail',
]);
~~~
### 關聯
這個例子,將為模型添加關聯。`create`?方法創建多模型時,返回 Eloquent?[實例集合](http://www.hmoore.net/tonyyu/laravel_5_6/786274),這樣就可以在集合上使用?`each`?等便利方法:
~~~
$users = factory(App\User::class, 3)
->create()
->each(function ($u) {
$u->posts()->save(factory(App\Post::class)->make());
});
~~~
#### 關聯 & 屬性閉包
模型工廠定義時,也可以使用閉包里的屬性來給模型添加關聯。比如,創建?`Post`?實例時,同時創建?`User`?實例,就可以這樣做:
~~~
$factory->define(App\Post::class, function ($faker) {
return [
'title' => $faker->title,
'content' => $faker->paragraph,
'user_id' => function () {
return factory(App\User::class)->create()->id;
}
];
});
~~~
這些閉包接收一個包含工廠屬性的數組:
~~~
$factory->define(App\Post::class, function ($faker) {
return [
'title' => $faker->title,
'content' => $faker->paragraph,
'user_id' => function () {
return factory(App\User::class)->create()->id;
},
'user_type' => function (array $post) {
return App\User::find($post['user_id'])->type;
}
];
});
~~~
## 可用的斷言方法
Laravel 為?[PHPUnit](https://phpunit.de/)?測試提供了多個數據庫斷言方法:
| 方法 | 描述 |
| --- | --- |
| `$this->assertDatabaseHas($table, array $data);` | 斷言數據庫表中含有指定數據。 |
| `$this->assertDatabaseMissing($table, array $data);` | 斷言數據庫表中不含有指定數據。 |
| `$this->assertSoftDeleted($table, array $data);` | 斷言數據庫中的指定記錄已軟刪除。 |
- 前言
- 翻譯說明
- 發行說明
- 升級指南
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- Homestead
- Valet
- 部署
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- Facades
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- URL
- Session
- 表單驗證
- 錯誤
- 日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全相關
- 用戶認證
- Passport OAuth 認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試相關
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Scout 全文搜索
- Socialite 社會化登錄