iT邦幫忙

2022 iThome 鐵人賽

DAY 29
0
DevOps

自動化測試大作戰系列 第 29

情境題—多重資料庫連線(二)

  • 分享至 

  • xImage
  •  

Medium 清新閱讀版連結

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

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

Migration 應對方式

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

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

    • SunnyProject 的 Migration 檔案複製到 MainProject 的 tests/migrations/sunny 資料夾下
    • 同時將 MoonProject 的 Migration 檔案複製到 MainProject 的 tests/migrations/moon 資料夾下
  • 建立一個 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。

  • 調整 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,
    ],
    
    // 下略
    
  • 調整 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)的方式,將原屬不同資料庫的不同資料表區隔開來,因此就算 MainProjectSunnyProject 都有 users 這個資料表,也會因為 SunnyProjectusers 資料表實際上會建立成 sunny_users ,因而不會產生衝突。

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

明天再讓我們探討其他情境。


上一篇
情境題—多重資料庫連線(一)
下一篇
情境題—Legacy:缺乏 Migration Files 與 Factory Files
系列文
自動化測試大作戰31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言