Files
a620906209 80f5cf179f
Run Tests / test (pull_request) Failing after 1m53s
chore(openspec): 歸檔 feature-test-coverage、provider-verification-workflow 變更
兩個 change 全任務完成(feature-test-coverage 40/40、provider-verification-workflow 48/48)。

同步規格:
- feature-test-coverage/spec.md 補齊 ## Requirements 區塊標頭(結構修正)
- Admin 教練審核 scenario 改為 approve 端點(toggle-verified 已由 #36 移除)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 19:19:52 +08:00

5.3 KiB
Raw Permalink Blame History

Context

現有 187 個 Feature test 分佈在認證、狀態機邊界、聊天授權等安全層,核心業務端點(Provider 課程管理、時段管理、Admin 使用者操作、通知觸發、預約列表)完全未覆蓋。缺口已於 2026-06-11 稽核報告中識別(通知系統「僅 Scheduler 路徑覆蓋」),此 change 補齊這五個區塊。

現有 Factory 狀況database/factories/ 只有 UserFactoryDivingOfferCourseScheduleBooking 均無 factory——現有測試一律使用 Model::create([...]) 直接建立,新測試沿用此慣例,不新增 factory(避免引入 app 行為)。

認證方式:現有 Feature test 全部使用 $this->actingAs($user) + getJson/postJson 等 HTTP helpers,不手動建立 token。新測試維持相同模式。

Goals / Non-Goals

Goals:

  • 5 個新 Feature test 類別:ProviderOfferCrudTestProviderScheduleCrudTestAdminUserManagementTestNotificationTriggerTestBookingListTest
  • 涵蓋正常流程(happy path)+ 所有權邊界(403+ 輸入驗證(422)
  • 通知測試補齊直接事件路徑(建立/確認/拒絕/取消),不只驗證 Scheduler 完課路徑

Non-Goals:

  • 不修改任何 app 程式碼
  • 不補 Unit test(已於上一個 change 完成)
  • 不測試 UI / 前端行為
  • 不測試通知 Email 實際發送(notification-email 規格另有覆蓋)

Decisions

D1:延續現有 Feature test 架構,不引入 Service layer mock

現有測試全部使用 RefreshDatabase + 真實 DB,未 mock 任何 repository/service。維持一致性優先於執行速度——187 案例目前 42 秒,新增 ~50 案例後預估 55 秒以內,可接受。

替代方案mock Cache::tags()Notification。決議:Notification::fake() 繼續使用(現有慣例),Cache::tags() 讓它真實運行(Redis 在 Docker 中可用)。

D2:通知測試使用 Notification::fake() + assertSentTo()

現有 BookingSchedulerTest 已驗證 Scheduler 完課觸發通知。NotificationTriggerTest 補齊 controller 直接觸發的路徑(storeconfirmrejectmember cancelprovider cancel),同樣 fake 後斷言 Notification::assertSentTo(),不依賴 queue worker。

D3:預約列表測試不涵蓋分頁(暫緩 O3.2)

MemberBookingController::index() 目前為 ->get() 全量回傳(O3.2 未完成),測試僅斷言回傳正確的資料集合(data 陣列包含/不包含正確的 booking)。分頁斷言待 O3.2 實作後加入。

D4:所有權邊界是必測案例,非選測

Provider CRUD 的「他人不可操作」403 路徑在現有 BookingLifecycleTest 已有先例,這裡對 Offer 和 Schedule 同樣必須測。Admin 操作已有 AdminEndpointAuthTest 覆蓋角色層的 401/403AdminUserManagementTest 聚焦資料正確性與操作副作用(is_active 切換、is_verified 切換 + 快取清除)。

Risks / Trade-offs

  • Cache::tags() 與 driver 相容性phpunit.xml 設定 CACHE_STORE=array。Laravel 11 的 array store 繼承 TaggableStore,因此 Cache::tags(['diving_offers'])->flush() 在測試環境可正常執行(DivingOfferVisibilityTest::test_toggle_verified_takes_effect_immediately_despite_cache 已驗證)。真正的風險是:若未來 CI 或本機改用 filedatabase 等不支援 tags 的 driver,所有呼叫 Cache::tags() 的 controller 測試都會拋出 BadMethodCallException。→ 緩解:在 tasks 加上驗收項目,確認 phpunit.xmlCACHE_STOREarrayredis,並加入 README 說明。
  • Admin toggle-verified 的快取副作用驗證方式DivingOfferVisibilityTest 已有端對端驗證(toggle → 公開列表立即消失)。AdminUserManagementTest 不重複這個斷言,只驗證 is_verified 欄位變更與 HTTP 200 即可,避免測試重複。
  • Notification::fake() 無法驗證 mail 實際送出:這是刻意的邊界——只驗證通知物件被派發至正確收件者,不驗證 email 模板內容(屬於 notification-email 規格的範疇)。

各測試類別案例清單

測試類別 案例 涵蓋邊界
ProviderOfferCrudTest store 成功、缺必填 422、update 成功、update 他人 403、destroy 成功、destroy 他人 403、未認證 401 happy path + ownership + auth
ProviderScheduleCrudTest store 成功、store 他人課程 403、過去日期 422、update max_participants 成功、update 低於 current 422、update 他人 403、destroy 同時取消 bookings happy path + 容量不變式 + ownership
AdminUserManagementTest 列出 members 只含 member role、列出 providers 只含 provider role、toggle-active 改變 is_active、toggle-verified 改變 is_verified、非 admin 403 資料正確性 + 角色隔離
NotificationTriggerTest BookingCreated→provider、Confirmed→member、Rejected→member、CancelledByMember→provider、CancelledByProvider→member 5 條直接觸發路徑,收件者各不同
BookingListTest GET /api/member/bookingsMemberBookingController::index)、GET /api/provider/bookingsProviderBookingController::index)、GET /api/admin/bookingsAdminBookingController::index)——各建兩方資料斷言隔離、admin 全看、未認證 401 路由已確認存在;角色資料隔離邊界