2023-12-18|閱讀時間 ‧ 約 32 分鐘

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

前一篇我們介紹了在撰寫自動化測試時常使用的 Trait,今天則要來為大家介紹 Auth 相關測試可如何進行,同時為大家示範 RefreshDatabase 與 WithoutMiddleware 這兩個 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 ,使用它之後,測試就能順利進行了!

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

下一篇來測試「指令」吧!

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

參考資料

本系列文章目錄

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.