상태 구성과 시나리오 픽스처
auth/session, data fixture, external sandbox, assertion helper 경계를 테스트 환경 관점에서 정리합니다.
fixture는 편의성 도구가 아니라 상태 조립 계층입니다.
에이전틱 테스트 환경에서는 fixture가 많아질수록 중요한 것은 추상화가 아니라
어떤 상태를 누구 책임으로 만들었는가를 드러내는 일입니다.
권장 계층
| 계층 | 책임 | 예시 |
|---|---|---|
| base runtime | 브라우저/클라이언트 공용 설정 | locale, timezone, baseURL |
| identity fixture | 로그인 상태와 권한 | admin, member, readonly |
| domain state fixture | 데이터 생성과 도메인 헬퍼 | order 생성, subscription 시작 |
| external sandbox fixture | 결제/이메일/provider stub | sandbox customer, test inbox |
| assertion helper | 재사용 가능한 검증 조합 | toast 확인, table row 검증 |
브라우저 러너 예시
Playwright를 쓴다면 fixture는 이 정도 책임 분리면 충분합니다.
import { test as base } from '@playwright/test'
type Fixtures = {
adminPage: import('@playwright/test').Page
}
export const test = base.extend<Fixtures>({
adminPage: async ({ browser }, use) => {
const context = await browser.newContext({
storageState: 'auth/admin.json',
})
const page = await context.newPage()
await use(page)
await context.close()
},
})중요한 건 fixture가 "관리자 페이지를 편하게 연다"보다 어떤 identity state를 어떤 boundary에서 제공하는가를 분명히 한다는 점입니다.
auth / session 운영 원칙
- 로그인 UI는 인증 경로를 검증하는 probe에만 남기고 나머지는 재사용 상태를 기본으로 합니다.
- 관리자, 일반 사용자, 권한 제한 사용자 상태를 분리합니다.
- 만료 토큰, 강제 로그아웃, MFA는 전용 시나리오로 분리합니다.
- shared 환경에서 계정 잠금이나 rate limit을 유발하지 않도록 account pool을 둡니다.
fixture가 감추면 안 되는 것
- DB 직접 조작을 일반 helper 뒤에 숨기는 것
- 여러 도메인에 걸친 비즈니스 규칙을 한 fixture가 떠안는 것
- 긴 준비 절차 전체를 "한 줄 magic helper"로 감추는 것
- sleep과 retry를 fixture 내부에 묻어 flake 원인을 안 보이게 하는 것
시나리오 작성 규칙
- probe 제목에 비즈니스 의도를 넣습니다.
- Given/When/Then 흐름이 로그만 봐도 이해되어야 합니다.
- 시나리오 하나는 실패 원인 하나에 가깝게 유지합니다.
- 여러 assertion을 넣더라도 같은 release 의미를 가지는 것끼리만 묶습니다.
리뷰 체크리스트
- fixture가 실제 실패 원인을 숨기지 않는가?
- identity, domain state, external sandbox 책임이 섞여 있지 않은가?
- cleanup 또는 TTL 전략이 명확한가?
- browser probe와 API/workflow probe가 동일한 seed vocabulary를 공유하는가?
anti-pattern
- global fixture에서 모든 데이터를 자동 생성
- one-size-fits-all page object
- helper 한 줄로 10개의 비즈니스 단계를 감추는 구조
- 시나리오보다 fixture가 더 큰 권한을 갖는 상태