iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 17
1
Software Development

如何一步步實踐TDD (測試驅動開發)系列 第 17

TDD 實戰 D3:Laravel 資料庫 (2)

今天要來繼續修改昨天建置資料庫的部分,有太多需要人工處理的步驟,期望讓幾乎全部都能自動化。

  • 關於 如何使用範例程式碼,請參考 TDD 實戰 D1
    • 本篇版本包含:4c

RefreshDatabase 與 Migrate

Laravel 5.5 新增了 RefreshDatabase trait [1],用途是在測試時將資料表內容清空。

在測試類別中 use RefreshDatabase,該類別的所有測試函數,每一次的前與後都會先清空表格,確保每個測試函數都能有相同的起始條件。

同時 RefreshDatabase 還會自動幫忙把空的資料庫 migrate 到最新的狀態,省掉了手動 migrate 的步驟。

理所當然在加入這行程式後,對昨天的程式碼執行測試會變得不通過,因為昨天的那筆 "Hello, I'm Louis." 是我們手動加入的,此時就被 RefreshDatabase 刪掉了。

sqlite

資料現在已經會透過 RefreshDatabase 自動 migrate 產生了,但是資料的檔案並不會。

所以我們的 sqlite 檔案依舊先手動建立:

$ sqlite3 database/database.sqlite

phpunit.xml 與 .env

由於 .env 應該是要存放著供產品階段使用的環境設定,因此來把 sqlite 改成只在測試時會使用。

<php> 中加入 <env> 來加入,同時 force 參數是代表會覆寫,預設則是會優先使用 .env 已有的設定。

<php>
    <env name="DB_CONNECTION" value="sqlite" force="true"/>
    <env name="DB_DATABASE" value="database/database.sqlite" force="true" />
</php>

現在即使把昨天在 .env 中刪掉的部分加回去,測試時也可以正常運作了。

Factory

Factory 模型工廠,是用來產生假的 Model instance,昨天在利用 artisan 建立 Model 檔案時,其中的 -f 參數就是代表同時也建立相對應的 Factory 函式的檔案。

還可以搭配 Faker 自動生成假資料,不過先一步一步來。

<?php
use App\Post;

$factory->define(Post::class, function () {
    return [
        'post_text' => "Hello, I'm Louis."
    ];
});

PostTest::testInsertPost

重構

由於產品程式已經在前一天寫完了,說是 TDD 的紅燈,不如說是 Refactor 重構,來的更適合。

class PostTest extends TestCase
{
    use RefreshDatabase;

    public function testInsertPost()
    {
        $post = factory(Post::class)->create();
        
        $this->assertDatabaseHas('posts', [
            'post_text' => "Hello, I'm Louis."
        ]);
    }
}

利用 factory 及 create() 來創建 $post 並加入這筆資料。

接著發現 testInsertPost 通過了,但是 testAllPost 卻沒通過。

PostTest::testAllPost

重構

testAllPost 會無法通過的原因,是我們剛剛加入的 use RefreshDatabase;,資料表每個測試函數的前後都會清空。

所以我們也在這裡使用 factory 來加入一筆資料。

class PostTest extends TestCase
{
    use RefreshDatabase;

    public function testAllPost()
    {
        $post = factory(Post::class)->create();
        
        $response = $this->get('/posts/');
        $response->assertStatus(200);
        $response->assertSee('All Posts:');

        $response->assertSee("Hello, I'm Louis.");
    }
}

( $ git checkout 4c )

完成!

終於不需要再手動進行那麼多步驟了!只剩下唯一的一步:自動建立測試用的資料庫,讓明天的我來接棒。


附註

  1. Trait 是 PHP 中用來做多重繼承的 interface,使用方法是在類別中 use some_trait,並且跟 namespace 的 use 是不同的語法。

上一篇
TDD 實戰 D2:Laravel 資料庫 (1)
下一篇
TDD 實戰 D4:Laravel 資料庫 (3)
系列文
如何一步步實踐TDD (測試驅動開發)30

尚未有邦友留言

立即登入留言