PHPUnit 自動化測試大作戰【CH29】

更新於 發佈於 閱讀時間約 13 分鐘

在前一篇文章中,我們探討了多重資料庫連線情境下,Model 及 Database Assertion 的應對方式,不過實際上筆者認為比較有難度的,其實是 Migration 應對方式

今天就讓我們來探討這部分吧!

Migration 應對方式

對於多重資料庫連線這種情境,筆者實務上做過的對應方式大致如下:

a. 將其他專案程式庫的 Migration 檔收集起來,放到主專案程式庫中的某個位置,並依不同專案程式庫設置不同資料夾存放。

  • 將 SunnyProject 的 Migration 檔案複製到 MainProject 的 tests/migrations/sunny 資料夾下
  • 同時將 MoonProject 的 Migration 檔案複製到 MainProject 的 tests/migrations/moon 資料夾下

b. 建立一個 RefreshMigrationTrait 類別,放置於 tests/Traits 之下:

  • tests/Traits/RefreshMigrationTrait.php
<?php

namespace Tests\Traits;

trait RefreshMigrationTrait{

public function refreshDatabase(): void {

$this->artisan('migrate:refresh', [

'--database' => 'mysql',

'--path' => 'database/migrations'

]); $this->artisan('migrate:refresh', [

'--database' => 'mysql_sunny',

'--path' => 'database/migrations/sunny'

]); $this->artisan('migrate:refresh', [

'--database' => 'mysql_moon',

'--path' => 'database/migrations/moon'

]); }}

在以上程式碼中,會執行3次 Migrate Refresh,第1次是針對 MainProject 的 Migration 檔案進行 Migrate Refresh,第2次是針對 SunnyProject 的 Migration 檔案進行 Migrate Refresh,第3次是針對 MoonProject 的 Migration 檔案進行 Migrate Refresh。

c. 調整 config/database.php

'mysql' => [

'driver' => env('DB_DRIVER', 'mysql'), // 原預設是 'mysql',改為由env注入

'database' => env('DB_DATABASE', 'forge'),

'host' => env('DB_HOST', '127.0.0.1'),

'port' => env('DB_PORT', '3306'),

'database' => env('DB_DATABASE', 'forge'),

'username' => env('DB_USERNAME', 'forge'),

'password' => env('DB_PASSWORD', ''),

'unix_socket' => env('DB_SOCKET', ''),

'charset' => 'utf8mb4',

'collation' => 'utf8mb4_unicode_ci',

'prefix' => env('DB_PREFIX', ''), // 由env注入

'strict' => false,

'engine' => null,

],'mysql_sunny' => [

'driver' => env('DB_SUNNY_DRIVER', 'mysql'), // 原預設是 'mysql',改為由env注入

'database' => env('DB_SUNNY_DATABASE', 'forge'),

'host' => env('DB_SUNNY_HOST', '127.0.0.1'),

'port' => env('DB_SUNNY_PORT', '3306'),

'database' => env('DB_SUNNY_DATABASE', 'forge'),

'username' => env('DB_SUNNY_USERNAME', 'forge'),

'password' => env('DB_SUNNY_PASSWORD', ''),

'unix_socket' => env('DB_SUNNY_SOCKET', ''),

'charset' => 'utf8mb4',

'collation' => 'utf8mb4_unicode_ci',

'prefix' => env('DB_SUNNY_PREFIX', ''), // 由env注入

'strict' => false,

'engine' => null,

],'mysql_moon' => [

'driver' => env('DB_MOON_DRIVER', 'mysql'), // 原預設是 'mysql',改為由env注入

'database' => env('DB_MOON_DATABASE', 'forge'),

'prefix' => env('DB_MOON_PREFIX', ''),

'host' => env('DB_MOON_HOST', '127.0.0.1'),

'port' => env('DB_MOON_PORT', '3306'),

'database' => env('DB_MOON_DATABASE', 'forge'),

'username' => env('DB_MOON_USERNAME', 'forge'),

'password' => env('DB_MOON_PASSWORD', ''),

'unix_socket' => env('DB_MOON_SOCKET', ''),

'charset' => 'utf8mb4',

'collation' => 'utf8mb4_unicode_ci',

'prefix' => env('DB_MOON_PREFIX', ''), // 由env注入

'strict' => false,

'engine' => null,

],// 下略

d. 調整 phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false">

<!---->

<php>

<env name="DB_DATABASE" value=":memory:"/>

<env name="DB_DATABASE_SUNNY" value=":memory:"/> // 增加此項

<env name="DB_DATABASE_MOON" value=":memory:"/> // 增加此項

<env name="DB_PREFIX_SUNNY" value="sunny_"/> // 增加此項

<env name="DB_PREFIX_MOON" value="moon_"/> // 增加此項

<env name="DB_DRIVER" value="sqlite"/>

<env name="DB_DRIVER_SUNNY" value="sqlite"/> // 增加此項

<env name="DB_DRIVER_MOON" value="sqlite"/> // 增加此項

<!---->

</php>

</phpunit>

做好以上調整後,當日後需要做多重資料庫測試時,我們便可使用以下方式,在每次測試執行前進行資料庫重建:

<?php

namespace Tests\Unit;

use Tests\TestCase;

use Tests\Traits\RefreshMigrationTrait

class ExampleTest extends TestCase

{ use RefreshMigrationTrait;

public function setUp(): void {

// 重建測試資料庫

$this->refreshDatabase();

} // 下略

}

這種實作及設定方式,會將3個專案的資料庫都建在 SQLite 上(藉由改變各連線的 Driver 值),再用設定前綴(Prefix)的方式,將原屬不同資料庫的不同資料表區隔開來,因此就算 MainProject 與 SunnyProject 都有 users 這個資料表,也會因為 SunnyProject 的 users 資料表實際上會建立成 sunny_users ,因而不會產生衝突。

以上就是今天的介紹,希望對大家的實務應用上有所幫助,也歡迎大家分享其它有用的應對方式唷!

下一篇再讓我們探討其他情境。

如果您喜歡這篇文章,歡迎加入追蹤以接收新文章通知 😄

本系列文章目錄

avatar-img
8會員
313內容數
歡迎來到 WilliamP 的沙龍天地,在這裡將與各位讀者探討各種主題,包刮高中數學題庫、PHP開發經驗、LINE聊天機器人開發經驗、書摘筆記等,歡迎交流!
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
WilliamP的沙龍 的其他內容
今天讓我們探討「缺乏 Migration Files 與 Factory Files」的 Legacy 情境吧! 很多時候我們會遇到沒有 Migration Files 或 Factory Files 的 Legacy Codebase,原因大概有以下幾種: 該程式庫原本不是以 Laravel
在實務情境上,常會有在單一專案程式庫中,存取多個不同資料庫的使用情境,在這種情況下,我們通常會設置多個資料庫連線(Database Connection)設定。 在平常開發使用設很方便,但要做測試時就會發現一些問題: 在測試程式碼或 Seeder 中調用 factory() 時,都是在預設連線資
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 這次同樣地,先讓我們規畫擬訂測試案例: 測試案例 使用者註冊: 使用者可送出註冊資料,系統將建立使用者資料,並送出含有專屬驗證連結之驗證信,當此驗證連結被開啟後,將讓使用者轉為已驗證狀態 請求錯誤的驗證連結: 錯誤的驗證連結被開啟後
前兩天,我們探討了「網站文章」的情境題;今明兩天,就讓我們探討另一個情境題「會員註冊」吧! 這邊我們同樣假設網站是採前後端分離的設計,因此我們就專注在測試 API 的部分,不過會多一個「註冊驗證信」的部分要實作與做測試驗證。 使用案例 使用者可填寫註冊資料後送出資料。 使用者可收到註冊驗證信
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 先讓我們規畫擬訂測試案例: 測試案例 當使用者瀏覽文章清單頁時: 使用者可看到所有文章清單,也就是【文章清單API】要能確實將資料庫內的文章資料,筆數不多不少地回應出來。 當使用者瀏覽單一文章頁時: 使用者可看到該文章資料,也就是【
在前面的篇幅中,與大家分享了許多撰寫 PHPUnit 測試程式碼所需的知識,之後的文章就讓我們來來模擬一些情境題,並在這些情境題底下,實際去設計測試案例函數吧! 作為第一個情境題,我們就選「網站文章」來當作第一個挑戰吧! 這邊我們假設網站是採前後端分離的設計,因此我們就專注在測試 API 的部分
今天讓我們探討「缺乏 Migration Files 與 Factory Files」的 Legacy 情境吧! 很多時候我們會遇到沒有 Migration Files 或 Factory Files 的 Legacy Codebase,原因大概有以下幾種: 該程式庫原本不是以 Laravel
在實務情境上,常會有在單一專案程式庫中,存取多個不同資料庫的使用情境,在這種情況下,我們通常會設置多個資料庫連線(Database Connection)設定。 在平常開發使用設很方便,但要做測試時就會發現一些問題: 在測試程式碼或 Seeder 中調用 factory() 時,都是在預設連線資
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 這次同樣地,先讓我們規畫擬訂測試案例: 測試案例 使用者註冊: 使用者可送出註冊資料,系統將建立使用者資料,並送出含有專屬驗證連結之驗證信,當此驗證連結被開啟後,將讓使用者轉為已驗證狀態 請求錯誤的驗證連結: 錯誤的驗證連結被開啟後
前兩天,我們探討了「網站文章」的情境題;今明兩天,就讓我們探討另一個情境題「會員註冊」吧! 這邊我們同樣假設網站是採前後端分離的設計,因此我們就專注在測試 API 的部分,不過會多一個「註冊驗證信」的部分要實作與做測試驗證。 使用案例 使用者可填寫註冊資料後送出資料。 使用者可收到註冊驗證信
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 先讓我們規畫擬訂測試案例: 測試案例 當使用者瀏覽文章清單頁時: 使用者可看到所有文章清單,也就是【文章清單API】要能確實將資料庫內的文章資料,筆數不多不少地回應出來。 當使用者瀏覽單一文章頁時: 使用者可看到該文章資料,也就是【
在前面的篇幅中,與大家分享了許多撰寫 PHPUnit 測試程式碼所需的知識,之後的文章就讓我們來來模擬一些情境題,並在這些情境題底下,實際去設計測試案例函數吧! 作為第一個情境題,我們就選「網站文章」來當作第一個挑戰吧! 這邊我們假設網站是採前後端分離的設計,因此我們就專注在測試 API 的部分
你可能也想看
Google News 追蹤
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
軟體系統的發展歷程大多相似,首重解決基本需求、提供操作介面,進而提升安全性、擴充功能、優化操作。
※ 什麼是資料庫正規化?為什麼需要正規化? 什麼是資料庫正規化? 資料庫正規化是一種設計關聯式資料庫的方法,目的是建立良好結構的關聯表,主要目的有二: 去除重複性:建立沒有重複的關聯表。因為重複資料不只浪費資料庫的儲存空間,而且會產生資料維護上的問題。 去除不一致的相依性:資料相依是指關聯表
改版之後的方格子,找不到圖庫,找不到路徑 只好發個測試廢文
Thumbnail
※ 基本操作:SQL 語法,SELECT, WHERE, CREATE, UPDATE, DELETE。 SELECT:從資料庫中或資料表中指定要選擇的欄位中取得資料,稱之為查詢 (query)。 ※ 語法:要由兩部分構成,第一部分是要 "拿什麼" 資料 (若有多項用逗號隔開);第二部分則為
Thumbnail
這是一篇很精彩的測試文章喔!
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
軟體系統的發展歷程大多相似,首重解決基本需求、提供操作介面,進而提升安全性、擴充功能、優化操作。
※ 什麼是資料庫正規化?為什麼需要正規化? 什麼是資料庫正規化? 資料庫正規化是一種設計關聯式資料庫的方法,目的是建立良好結構的關聯表,主要目的有二: 去除重複性:建立沒有重複的關聯表。因為重複資料不只浪費資料庫的儲存空間,而且會產生資料維護上的問題。 去除不一致的相依性:資料相依是指關聯表
改版之後的方格子,找不到圖庫,找不到路徑 只好發個測試廢文
Thumbnail
※ 基本操作:SQL 語法,SELECT, WHERE, CREATE, UPDATE, DELETE。 SELECT:從資料庫中或資料表中指定要選擇的欄位中取得資料,稱之為查詢 (query)。 ※ 語法:要由兩部分構成,第一部分是要 "拿什麼" 資料 (若有多項用逗號隔開);第二部分則為
Thumbnail
這是一篇很精彩的測試文章喔!