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

因為 ORM 已經幫我們實作 Model 存取資料的相關機制,我們只是先測試驗證它沒有問題;所以實際上不需要特別測試 Model ,這裡只是為了確認測試是可以正確運作的。

好的 Pattern 是用 Repository 把 Model 封裝起來。

results matching ""

    No results matching ""