Model
針對 model 資料存取做測試
測試資料庫存取時,要儘可能不動到正式資料庫,而且要能快速建立
也儘可能把設定都放在測試可控制的環境,不要跟主程式有牽扯。
- 定義測試用資料庫
- 使用 sqlite
:memory:
來測試
建立 Article model :
$ cd demo
$ php artisan make:model Article
在 Article.php
加入以下屬性:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model {
// 定義當使用 __construct($data) 或 create($data) 時
// 可以被修改的欄位,進而保護其他欄位不被修改
protected $fillable = ['title', 'body'],
}
- 建立
app/Article.php
- 建立
database/migrations/xxxx_xx_xx_xxxxxx_create_articles_table.php
修改 tests/TestCase.php
,加入:
use Illuminate\Support\Facades\Artisan;
class TestCase extends Illuminate\Foundation\Testing\TestCase {
// ...
// 每個 test case 都會重新初始化資料庫
protected function initDatabase()
{
// 在測試時動態修改 config
// 使其連接 sqlite
config([
'database.default' => 'sqlite',
'database.connections.sqlite' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
]);
// 呼叫 php artisan migrate
// 及 php artisan db:seed
Artisan::call('migrate');
Artisan::call('db:seed');
}
// 重置資料庫
// 讓下次測試不會被舊資料干擾
protected function resetDatabase()
{
// 呼叫 php artisan migrate:reset
// 這樣會把所有的 migration 清除
Artisan::call('migrate:reset');
}
新增 tests/ArticleTest.php
,並加入初始化資料庫的動作:
class ArticleTest extends TestCase
{
// setUp 每執行一次 test case 前都會執行
// 可以用來初始化資料庫並重新建立待測試物件
// 以免被其他 test case 影響測試結果
public function setUp()
{
// 一定要先呼叫,建立 Laravel Service Container 以便測試
parent::setUp();
// 每次都要初始化資料庫
$this->initDatabase();
}
// tearDown 會在每個 test case 結束後執行
// 可以用來重置相關環境
public function tearDown()
{
// 結束一個 test case 都要重置資料庫
$this->resetDatabase();
}
}
先測試沒有文章:
class ArticleTest extends TestCase
{
// 測試如果文章為空
public function testEmptyResult()
{
// 取得所有文章
$articles = Article::all();
// 確認 $articles 是 Collection
$this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $articles);
// 而文章數為 0
$this->assertEquals(0, count($articles));
}
}
測試新增資料並列出:
class ArticleTest extends TestCase
{
// ...
// 測試新增資料並列出
public function testCreateAndList()
{
// 新增 10 筆資料
for ($i = 1; $i <= 10; $i ++) {
Article::create([
'title' => 'title ' . $i,
'body' => 'body ' . $i,
]);
}
// 確認有 10 筆資料
$articles = Article::all();
$this->assertEquals(10, count($articles));
}
}
執行測試:
$ ./vendor/bin/phpunit
- 使用 globally installed 的 phpunit 會有 error
- https://github.com/laravel/framework/issues/7299
因為 ORM 已經幫我們實作 Model 存取資料的相關機制,我們只是先測試驗證它沒有問題;所以實際上不需要特別測試 Model ,這裡只是為了確認測試是可以正確運作的。
好的 Pattern 是用 Repository 把 Model 封裝起來。