Laravel資料庫測試
在測試方面,Laravel
內建使用PHPUnit
提供了非常方便的解決方案。而對於資料庫增刪改查的測試,要解決的一個很重要的問題就是如何在測試完成之後,恢復資料庫的原貌,例如要測試一個使用者註冊的方法,需要插入一條使用者記錄到資料庫,但是測試完成之後,我們並不想讓這條測試用例儲存在資料庫裡。為了解決這個問題,Laravel
提供了非常方便的方案:
- 使用遷移:
DatabaseMigrations
- 使用事務:
DatabaseTransactions
參考資料:https://laravel.com/docs/5.3/database-testing#resetting-the-database-after-each-test
另外一種解決方案:使用SQLite
的記憶體資料庫:memory:
Laravel
提供的兩種解決方案,仍然對資料庫進行了讀寫操作,某些時候你可能並不想這樣(例如多人共享一個線上開發資料庫),此時,還可以用一種更為優雅的方式:SQLlite
,邏輯其實也非常簡單:就是在跑測試用例的時候,將資料庫的連線替換為SQLite
。
使用示例
例如我們有以下測試類(該事例並不具有代表性,僅用於說明問題,並假設本機已經安裝SQLite
):
class HomePageTest extends TestCase {
public function testHomePage()
{
// 建立一個測試使用者,並儲存
$user = factory(AppUser::class)->create();
$this->actingAs($user)->visit(`/home`)->see(`Dashboard`);
}
}
- 首先在
Laravel
的資料庫配置檔案,即config/database.php
的connections
陣列中新增一個新的資料庫連線
`sqlite` => [
`driver` => `sqlite`,
`database` => `:memory:`,
`prefix` => ``,
],
這裡一個非常重要的引數就是`database` => `:memory:`
,:memory:
資料庫是SQLite
中內建的一個記憶體資料庫,每次執行測試用例的時候都會在記憶體中建立一個新的資料庫,並在測試完成關閉資料庫連線後,自動清除掉,具有良好的隔離性,又因為是在記憶體中的,所以速度也很快,這些特性對於測試非常方便,這也是我們選用SQLite
資料庫作為測試庫的一個非常重要的原因。有關詳細解釋,點選這裡。
- 然後需要修改
PHPUnit
的配置檔案,在phpunit.xml
中,將資料庫連線改為剛剛定義的SQLite
連線
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<!-- 將資料庫連線改為剛剛定義的SQLite連線 -->
<env name="DB_CONNECTION" value="sqlite" />
</php>
這會覆蓋.env
中定義的資料庫連線DB_CONNECTION=mysql
,並告訴框架在執行測試的時候,用sqlite
連線代替mysql
連線。
- 最後需要在執行測試用例之前執行資料庫遷移,在測試類的基類,即
TestCase.php
中新增setUp
方法
public function setUp()
{
parent::setUp();
// 執行資料庫遷移
$this->artisan(`migrate`);
}
這樣在每次執行測試用例之前,都會向SQLite
的:memory:
資料庫中執行所有的遷移,生成業務邏輯所需的資料表。
方案優缺點
- 該方案關鍵點在於使用
SQLite
內建的一個記憶體資料庫:memory:
,因此速度比較快,有很好的隔離性,也不會對我們的開發資料庫有任何的影響。 - 當然該方案也有缺點,假如專案的資料庫龐大,有大量的資料表或者遷移檔案,會消耗大量記憶體,當執行測試的時候可能會由於記憶體不足,導致測試中斷。此時需要為PHP分配合適的記憶體,在
php.ini
中修改配置memory_limit = 128M