iT邦幫忙

2022 iThome 鐵人賽

DAY 10
0

Medium 清新閱讀版連結

前一天我們介紹了在撰寫自動化測試時常使用的 Trait,今天則要來為大家介紹 Auth 相關測試可如何進行,同時為大家示範 RefreshDatabaseWithoutMiddleware 這兩個 Trait 的使用。

取得當前登入使用者資料

在以 Laravel 開發 Web 服務時,常常以 Auth::user() 這個方式,來取得當前登入 Session、當前 API 請求 Token 所關聯之使用者資料,然而在撰寫測試時,如果還要先進行模擬輸入帳密與送出登入請求,並從回應中取出 Session ID 之 Cookie 或是 API Token,再帶入實際要進行測試的行為中,那會是一個挺麻煩的事情。有鑑於此,Laravel 在提供了兩個函數:

  • $this->actingAs(UserContract $user, $guard = null)
  • $this->be(UserContract $user, $guard = null)

這兩個函數的功能完全一樣(實際上 $this->actingAs() 裡面就是呼叫$this->be()),都是可以讓我們設定當前要模擬的登入/Auth之使用者。以下就讓我們看看如何使用吧!(由於官方文件主要是使用 $this->actingAs(),因此以下範例也主要會使用 $this->actingAs()

  • routes/web.php

    <?php
    
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Auth;
    use Illuminate\Support\Facades\Route;
    
    Route::get('/me/profiles', function (Request $request) {
        $user = Auth::user();
    
        $profile = [
            'name' => $user->name,
            'email' => $user->email,
        ];
    
        return response()->json(['profile' => $profile]);
    })->name('get.me.profile')
    	->middleware(['auth']);
    

    在以上的程式碼中,我們實作了一個 API 端點,此端點可取得當前所登入的 User 個人檔案資料,並且以JSON格式回應。

  • tests/Feature/AuthTest.php

    <?php
    
    namespace Tests\Feature;
    
    use App\Models\User;
    use Illuminate\Foundation\Testing\RefreshDatabase;
    use Tests\TestCase;
    
    class AuthTest extends TestCase
    {
        use RefreshDatabase
    
        public function testGetLoggedInUserProfile()
        {
            $user = User::factory()->create();
    
            $this->actingAs($user)->get(route('get.me.profile'))
                ->assertJson([
                    'profile' => [
                        'name' => $user->name,
                        'email' => $user->email,
                    ]
                ]);
        }
    }
    

    以上測試程式碼,我們建立了一筆假資料 $user,並將其設定為當前登入之 User ,並測試是否以 get.me.profile 這個 API 端點取得使用者個人檔案資料。同時,因為我們有建立假資料,為不讓其他測試案例與此測試案例產生交互影響,我們使用了 這個 RefreshDatabase Trait ,在每個 tests/Feature/AuthTest.php 裡的測試被執行的前後重置資料庫。

略過 Middleware

在前一天文章有提到,有時我們想測試的功能會經過一些 Middleware 的處理,有可能會需要做些特別設定,才可以正常使用欲測試的功能,但 Middleware 的處理邏輯可能不是當下想測試的重點,此時便可使用 WithoutMiddleware 來略過 Middleware 。

  • app/Http/Middleware/ForbidLoginDuringLunch.php

    <?php
    
    namespace App\Http\Middleware;
    
    use Carbon\Carbon;
    use Closure;
    use Illuminate\Http\Request;
    
    class ForbidLoginDuringLunch
    {
        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
         * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
         */
        public function handle(Request $request, Closure $next)
        {
            $hour = Carbon::now()->hour;
    
            if ($hour <= 14 && $hour >= 12) {
                return response()->json(['error' => 'No lunch login'], 403);
            }
    
            return $next($request);
        }
    }
    

    以上程式碼實作了一個 Middleware,這個 Middleware 會檢查當下時間是否介於 12~14點之間,如果是則回應 403,相當於禁止於午休時段登入網站(會不會真的有網站實作這種 Middleware?)。

  • routes/web.php

    <?php
    
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Auth;
    use Illuminate\Support\Facades\Route;
    
    Route::get('/me/profiles', function (Request $request) {
        $user = Auth::user();
    
        $profile = [
            'name' => $user->name,
            'email' => $user->email,
        ];
    
        return response()->json(['profile' => $profile]);
    })->name('get.me.profile')
    	->middleware(['auth', 'no.lunch.login']); // 新增 no.lunch.login Middleware
    

    以上程式碼和前一個案例大致相同,只不過多套用了 no.lunch.login 這個 Middleware。

  • tests/Feature/AuthTest.php

    <?php
    
    namespace Tests\Feature;
    
    use App\Models\User;
    use Illuminate\Foundation\Testing\RefreshDatabase;
    use Illuminate\Foundation\Testing\WithoutMiddleware;
    use Tests\TestCase;
    
    class AuthTest extends TestCase
    {
        use RefreshDatabase;
        use WithoutMiddleware;
    
        public function testGetLoggedInUserProfile()
        {
            $user = User::factory()->create();
    
            $this->actingAs($user)->get(route('get.me.profile'))
                ->assertJson([
                    'profile' => [
                        'name' => $user->name,
                        'email' => $user->email,
                    ]
                ]);
        }
    }
    

    以上程式碼和前一個案例大致相同,但多使用了 WithoutMiddleware ,使用它之後,測試就能順利進行了!

以上就是今天的介紹了!不知道大家還能消化嗎?(當時筆者可是花了不少時間才了解…..)

明天來測試「指令」吧!

參考資料


上一篇
自動化測試相關Traits介紹
下一篇
指令測試
系列文
自動化測試大作戰31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言