iT邦幫忙

2022 iThome 鐵人賽

DAY 11
0

Medium 清新閱讀版連結

指令在現代 Laravel Web Applications 中,也是一個相當常見的應用,而 Laravel 也為此準備許多方便實現測試的函數,以下就來為大家介紹

  1. artisan()
    • 函數簽名:artisan($command, $parameters = [])
    • 函數說明:這應該是指令測試中最重要的一個!此函數可以在測試程式碼中,執行參數1 $command 的指令,並且帶入參數2 $parameters 所附含的指令參數鍵值對。
  2. assertSuccessful()
    • 函數簽名:assertSuccessful()
    • 函數說明:此函數需接在 $this→artisan() 之後,它可以驗證指令是否成功執行完畢,並且回應 exit code 0(exit code 0 一般代表程式執行完畢且無錯誤或例外發生)。
  3. assertFailed()
    • 函數簽名:assertFailed()
    • 函數說明:此函數需接在 $this→artisan() 之後,它可以驗證指令是否非成功執行完畢,只要指令不是回應 exit code 0 ,就會被當 Failed
  4. expectsConfirmation()
    • 函數簽名:expectsConfirmation($question, $answer = 'no')
    • 函數說明:此函數需接在 $this→artisan() 之後,可以驗證是否有預期中的確認訊息輸出。
  5. expectsQuestion()
    • 函數簽名:expectsQuestion($question, $answer)
    • 函數說明:此函數需接在 $this→artisan() 之後,可以驗證是否有預期中的詢問訊息輸出。
  6. expectsOutput
    • 函數簽名:expectsQuestion($output)
    • 函數說明:此函數需接在 $this→artisan() 之後,可以驗證是否有預期中的文字詢息輸出。

介紹完指令相關的測試函數,以下就舉個例子,來為大家展示實務應用吧!

  • app/Console/Commands/DeleteUser.php

    <?php
    
    namespace App\Console\Commands;
    
    use App\Models\User;
    use Illuminate\Console\Command;
    use Illuminate\Support\Facades\Log;
    
    class DeleteUser extends Command
    {
        /**
         * The name and signature of the console command.
         *
         * @var string
         */
        protected $signature = 'delete-user {userId}';
    
        /**
         * The console command description.
         *
         * @var string
         */
        protected $description = 'Delete the user of given id';
    
        /**
         * Execute the console command.
         *
         * @return int
         */
        public function handle(): int
        {
            $userId = $this->argument('userId');
    
            $user = User::find($userId);
    
            if (empty($user)) {
                $this->warn('User not found!');
    
                return 1;
            }
    
            if (!$this->confirm('Are you sure to delete this user?')) {
                return 1;
            }
    
            $logOptions = ['Console output', 'Log file'];
    
            $logType = $this->choice(
                'Please select log option:',
                $logOptions
            );
    
            $user->delete();
    
            $message = 'User deleted';
    
            if ($logType === $logOptions[0]) {
                $this->info($message);
            } else {
                Log::info($message, ['userId' => $userId]);
            }
    
            return 0;
        }
    }
    

    在以上程式碼中,我們實作了一個指令 DeleteUser ,當我們在命令列執行 php artisan delete-user {userId} 時,便會執行這個指令。這個指令有1個數入參數 userId ,其為欲刪除的 User 資料 ID。這個指令的功能與行為大致如下:

    • 以給定的 userId 嘗試撈取 User 資料,若無資料則顯示錯誤並結束指令,否則繼續流程。
    • 輸出 Are you sure to delete this user? 文字,讓使用者確認是否繼續執行刪除指令,並依使用者之回應決定提前結束指令或繼續流程。
    • 如使用者決定繼續流程,詢問使用者欲使用何種方式做記錄。
    • 刪除 User 資料
    • 依使用者所選擇的記錄方式執行記錄
    • 結束指令並回應 exit code 0
  • tests/Feature/CommandTest.php

    <?php
    
    namespace Tests\Feature;
    
    use App\Models\User;
    use Illuminate\Foundation\Testing\RefreshDatabase;
    use Tests\TestCase;
    
    class CommandTest extends TestCase
    {
        use RefreshDatabase;
    
        public function testUserNotFound()
        {
            $this->artisan('delete-user',['userId' => 1])
                ->expectsOutput('User not found!')
                ->assertFailed();
        }
    
        public function testSuccessDeleteUser()
        {
            $user = User::factory()->create();
            $userId = $user->id;
    
            $this->artisan('delete-user', ['userId' => $userId])
                ->expectsConfirmation(
                    'Are you sure to delete this user?', 'yes'
                )
                ->expectsQuestion('Please select log option:', 0)
                ->expectsOutput('User deleted')
                ->assertSuccessful();
    
            $this->assertDatabaseCount('users', 0);
        }
    
        public function testCancelDeleteUser()
        {
            $user = User::factory()->create();
            $userId = $user->id;
    
            $this->artisan('delete-user', ['userId' => $userId])
                ->expectsConfirmation('Are you sure to delete this user?')
                ->assertSuccessful();
    
            $this->assertDatabaseHas('users', [
                'id' => $userId,
            ]);
        }
    }
    

    以上測試程式碼,共分為3個測試案例情境:

    • 第1個測試案例 testUserNotFound(),測試的是當給定的 userId,無法在資料庫找到對應資料時,指令應有的對應行為與輸出
    • 第2個測試案例 testSuccessDeleteUser(),測試的是當給定的 userId,可在資料庫找到對應資料,且使用者於確認提示時輸入 yes後,指令應有的對應行為與輸出。
    • 第3個測試案例 testCancelDeleteUser(),測試的是當給定的 userId,可在資料庫找到對應資料,且使用者於確認提示時輸入 no 後,指令應有的對應行為與輸出。

以上就是針對指令測試的介紹,希望對各讀者有所幫助。

明天來介紹測試「失敗」吧!

參考資料


上一篇
Auth測試
下一篇
例外測試
系列文
自動化測試大作戰31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言