cc-e2e가 생성/수정하는 모든.feature파일은 조직 표준을 따릅니다. 본 문서는 저작 관점의 체크리스트이며, 원전(原典)은cc-flutter/skills/bdd-testing/SKILL.md입니다.
1. 언어 규칙 (조직 표준)#
모든 텍스트(Feature명, Scenario명, 설명, Step, Background)는 영어로 작성하고 # 한글 번역 주석을 덧붙입니다.
이유:
-
step 파일명은 영어 snake_case 로 손으로 작성 (
i_tap_the_login_button.dart, 코드 생성기 없음 — 네이밍은 사람이 이 규약을 따라 맞춘다) - step 함수명 영어 camelCase (
iTapTheLoginButton) 와 Gherkin 문장이 1:1 매칭되어야 함 - 조직 커밋
6003db6 refactor(testing): .feature 파일 언어 규칙 통일에서 명시적 확정
@smoke
@auth
Feature: Login Page # 로그인 페이지
Users can log in with email/password or social login. # 사용자가 이메일/비밀번호로 로그인하거나 소셜 로그인을 사용할 수 있습니다.
Background:
Given I am on the login page # 로그인 페이지에 있습니다
Scenario: Successful login with valid email # 유효한 이메일로 로그인 성공
When I enter { ' test@example.com ' } in the email field # 이메일 입력
And I enter { ' password123 ' } in the password field # 비밀번호 입력
And I tap the login button # 로그인 버튼 탭
Then the store screen is displayed # 스토어 화면 표시
Scenario: Form validation shows errors on empty submit # 빈 폼 제출 시 유효성 에러
When I tap the login button # 로그인 버튼 탭
Then the validation error should be displayed # 유효성 에러 표시
Scenario: Background resume preserves session # 백그라운드 복귀 시 세션 유지
When I press the home button # 홈 버튼
And I return to the app # 앱 복귀
Then the store screen is displayed # 스토어 표시
1.1 Business Value 문구 (권장)#
Feature 설명에 관점(역할)과 목적을 밝히면 시나리오의 "왜"가 분명해집니다. 필수는 아니지만, 여정(@journey)이나 기획/QA가 함께 검토하는 Feature에는 권장합니다:
Feature: Login Page # 로그인 페이지
As a returning user # 재방문 사용자로서
I want to log in with my email and password # 이메일과 비밀번호로 로그인하고 싶다
So that I can access my personalized store # 그래야 개인화된 스토어에 접근할 수 있다
2. 실행 대상 (조직 표준)#
.feature 시나리오는 Patrol E2E 테스트로만 검증합니다 — 사람이 손으로 app/{app}/integration_test/scenarios/
아래에 작성합니다(코드 생성기 없음, bdd_test_gen/co_test_gen/bdd_widget_test
어느 것도 이 파이프라인에 없습니다). 파일 배분은 §5.1 을 따릅니다 — 같은 Background 를 공유하는 Scenario 3건 이상이면 배치 파일
{name}_{screen}_batch_test.dart 하나로, @isolated 이거나 2건 이하면 {name}_{scenario}_test.dart
로 갑니다.
위젯 테스트 생성 경로는 폐지되었습니다 — 위젯 vs Patrol 을 고르는 @both/@widget-only/@patrol-only
태그는 더 이상 쓰지 않습니다. Gherkin 과 무관한 일반 위젯 테스트(순수 testWidgets, golden, BLoC 위젯
테스트)가 필요하면 BDD 와 별개로 cc-flutter/skills/widget-testing 규약을 따라 직접 작성합니다.
자세한 배경은 cc-flutter/skills/bdd-testing/SKILL.md, cc-flutter/skills/patrol-bdd-conventions/SKILL.md
참조.
3. 분류 태그#
| 태그 | 의미 |
|---|---|
@smoke | 매 PR 스모크 스위트 |
@regression | 야간 회귀 |
@journey | 다단계 사용자 여정 |
@slow | 실행 시간 긴 시나리오 |
@isolated |
화면 배치에서 제외 — 자기 patrolTest 로 단독 실행 (§5.1) |
@{domain} |
@auth, @store, @reader 등 도메인 |
Feature 상단에 도메인 태그 + 시나리오별로 @smoke 등 등급·스케줄 태그를 조합.
@isolated 는 등급·스케줄이 아니라 실행 구조를 가르는 태그입니다. 붙이지 않은 것이
기본값(= 배치 대상)이며, 필수 조건은 §5.1 에 있습니다. @journey 는 정의상 화면을 넘나들므로
@journey 가 붙으면 @isolated 도 함께 붙습니다.
4. Step 문장 규약#
형식#
- 영어 +
# 한글 번역 - 동사 현재형:
I tap,I enter,should be displayed - 파라미터:
{'value'}문법 (step 함수의 추가 인자로 추출됨)
Given / When / Then 사용#
- Given — 초기 상태 / 전제 (mock 주입, 로그인 상태 등)
- When — 사용자 조작 (탭, 입력, 스크롤)
- Then — 기대 결과 (요소 표시, 네비게이션, 에러 메시지)
- And / But — 이전 키워드 이어받기
step 파일명 매핑#
- Gherkin:
I tap the login button - 파일:
i_tap_the_login_button.dart - 함수:
iTapTheLoginButton
자세한 규약은 cc-flutter/rules/bdd-test-patterns.md 의 "Step File Naming Rules" 참조.
Data Table (Given 필드 2개 이상)#
하나의 Given에 넣을 필드가 2개 이상이면 인라인 나열 대신 데이터 테이블(세로 key-value)을 씁니다:
# ❌ Given에 필드를 길게 나열
Given a user wants to add a bookmark with URL " https://example.com " , title " Example " , and description " ... "
# ✅ 데이터 테이블로 정리
Given a user wants to add a bookmark with the following details: # 다음 정보로 북마크를 추가하려 함
| URL | https://example.com |
| Title | Example Website |
| Description | A helpful example |
5. 단일 책임 원칙#
1 Scenario = 1 행위 검증:
- ❌ "Login and edit profile and logout" — 하나의 시나리오에 3개 행위
- ✅ Scenario 3개로 분리
예외: 의도적 여정 검증 (@journey 태그) — cross-feature 스토리 확인 시에만.
폼 필드 입력은 단일 고수준 When + 도메인 Step으로 — 필드를 하나씩 채우는 When/And를 나열하지 말고, 값은 위 Data Table로 Given에 두고
When은 하나의 고수준 동작(도메인 step)으로 통합합니다:
# ❌ 필드마다 개별 When/And
When I enter { ' https://example.com ' } in the URL field
And I enter { ' Example Website ' } in the title field
And I enter { ' A helpful example ' } in the description field
And I tap the save button
# ✅ Given data table + 단일 When
Given a user wants to add a bookmark with the following details: # 다음 정보로 북마크를 추가하려 함
| URL | https://example.com |
| Title | Example Website |
| Description | A helpful example |
When they add the bookmark # 북마크를 추가함
허용 기준은 cc-flutter/skills/bdd-canonical-steps/SKILL.md 의 "도메인 특화 Step 허용 기준" — "복합 동작(3단계 이상)" 항목을 참조하세요. 단순 UI 이동 트레이스(화면 전환용 탭 나열)는 이 원칙의 대상이 아니며,
여러 값을 입력해 하나의 엔티티를 제출/저장하는 폼 시나리오에 적용합니다.
🔁 화면 배치는 이 원칙을 완화하지 않습니다. 배치가 합치는 것은 실행 세션이지 검증 단위가 아닙니다. "어차피 한 세션에서 도니까 한 Scenario 에 다 넣자" 는 정확히 반대 방향의 오독입니다 — 배치 덕분에 "쪼개면 도달 비용이 배로 든다"는 압력이 사라지므로, 이 원칙은 오히려 더 지키기 쉬워집니다. 잘게 쪼갠 Scenario 를 §5.1 대로 한
.feature에 모으세요.
5.1 화면 단위 배치 — .feature 를 도달 상태로 나눈다#
Patrol E2E 는 가장 비싼 테스트이고, 비용의 대부분은 도달(앱 기동 → 로그인 → 그 화면까지 내비게이션)입니다. 그래서 같은 도달 상태를 공유하는 시나리오는 한 번 도달해 연달아 돌립니다.
배치 단위를 Gherkin 이 이미 표현하고 있는데, 그게 Background 입니다:
배치 단위 = 하나의
.feature안에서 같은Background를 공유하는 Scenario 집합.
저작 규칙#
-
.feature는 "도달 상태(대개 화면)" 단위로 나눕니다. 서로 다른Background가 필요한 시나리오를 한 파일에 섞지 마세요 — 섞이는 순간 그 파일은 배치가 불가능해집니다. 한 기능에 화면이 여럿이면store_home.feature·store_detail.feature처럼 나눕니다. -
Background에는 도달까지만 적습니다. 검증은Background가 아니라 각 Scenario 에 둡니다. - 배치가 기본값입니다. 배치에 들어갈 수 없는 시나리오에만
@isolated를 답니다. -
하한선 3건 — 같은
Background를 공유하는 Scenario 가 3건 이상일 때만 배치 파일로 묶습니다. 2건 이하는 기존 1파일 1시나리오 그대로입니다.
⚠️ Background 의 실행 의미가 표준 Gherkin 과 다릅니다#
표준 Gherkin 은 Background 를 Scenario 마다 실행합니다. 이 조직의 배치 규약은
배치당 1회 실행하고, Scenario 사이에는 화면 리셋 step 을 돌립니다. .feature
를 읽는
사람이 표준 의미론을 가정하지 않도록 하는 의도적 이탈입니다.
@isolated 필수 조건#
하나라도 해당하면 배치에 넣지 않습니다:
- 인증 상태를 바꾼다 (로그아웃·계정 전환)
- 되돌릴 수 없는 서버 상태를 만든다 (결제·구매·삭제)
- 화면을 떠나 돌아오지 않는다 —
@journey는 정의상 해당 - 앱 재시작·프로세스 수준 상태가 검증 대상 (백그라운드 복귀·딥링크 콜드스타트·최초 권한 요청)
- 화면 리셋 계약(닫는다 · 되돌린다 · 단정한다)을 만족하는 리셋을 쓸 수 없다
@store
Feature: Store Home # 스토어 홈
As a signed-in reader # 로그인한 독자로서
I want to browse and filter the store # 스토어를 둘러보고 걸러내고 싶다
So that I can find a book to read # 그래야 읽을 책을 찾을 수 있다
# 이 Background 는 배치당 1회만 실행됩니다 (조직 규약, 표준 Gherkin 과 다름)
Background:
Given I am signed in # 로그인되어 있다
And I am on the store home # 스토어 홈에 있다
@smoke
Scenario: Search returns matching books # 검색 결과 표시
When I enter { ' flutter ' } in the search field # 검색어 입력
Then the search result list should be displayed # 검색 결과 목록 표시
Scenario: Category filter narrows the list # 카테고리 필터 적용
When I tap the category chip # 카테고리 칩 탭
Then the filtered list should be displayed # 걸러진 목록 표시
Scenario: Empty search shows the empty state # 결과 없음 상태
When I enter { ' zzzz ' } in the search field # 없는 검색어 입력
Then the empty state should be displayed # 빈 상태 표시
@isolated @journey
Scenario: Purchasing a book moves it to my library # 구매 후 내 서재로 이동
# 되돌릴 수 없는 서버 상태 + 화면 이탈 → 배치 불가
When I purchase the first book # 첫 번째 도서 구매
Then the my library screen is displayed # 내 서재 화면 표시
Patrol 쪽 대응(배치 파일 구조 · 리셋 계약 3항 · 실패/BLOCKED 의미론)의 정본은
cc-flutter/skills/patrol-bdd-conventions/SKILL.md 의 "화면 단위 배치" 절입니다.
6. Scenario Outline#
데이터 변형 자체가 검증 대상일 때만 사용합니다. 그 외에는 일반 Scenario가 기본값입니다 — 같은 로직을 값만 바꿔 반복할 필요가 없다면 Outline은 과잉입니다.
입력만 다른 반복 시 Scenario Outline + Examples:
Scenario Outline: Search returns results # 검색 결과 표시
When I enter { ' < query > ' } in the search field # 검색어 입력
Then < count > results should be displayed # < count > 개 결과 표시
Examples:
| query | count |
| flutter | 15 |
| patrol | 3 |
| xyz | 0 |
7. cc-e2e 특수 규칙#
초안 단계 경고 주석#
scenario-draft 가 생성한 .feature 는 상단에 경고 주석 포함:
# DRAFT — generated from flutter-skill exploration journal
# journal: .claude/e2e-journal/sign_in.jsonl
# generated: 2026-04-23T12:34:56Z
# ⚠️ Review and refine before /cc-e2e:lock.
scenario-lock 시 이 주석이 제거되어야 lock 허용.
파일 위치#
| 위치 | 용도 |
|---|---|
app/{app}/integration_test/features/{name}.feature |
유일한 위치 — single-feature 든 cross-feature 든 여기 하나뿐. 문서(빌드 대상 아님). 파일은 §5.1 대로 도달 상태(대개 화면) 단위 로 나눈다 |
app/{app}/integration_test/scenarios/{name}_{screen}_batch_test.dart |
대응하는 Patrol 테스트 — 같은 Background 를 공유하는 Scenario 3건 이상 (기본) |
app/{app}/integration_test/scenarios/{name}_{scenario}_test.dart |
대응하는 Patrol 테스트 — @isolated 이거나 2건 이하 |
feature 패키지(feature/{type}/{name}/) 안에는 .feature 도 test/src/bdd/
도 존재하지 않습니다.
scenario-draft 는 처음부터 위 위치에 생성하므로, 나중에 cross-feature 로 판명돼도 옮길 필요가
없습니다 — single-feature/cross-feature 구분이 목적지를 가르지 않습니다.
8. 금지 사항#
- ❌ Korean-only Gherkin (영어 + 한글 주석 조합 필수)
- ❌ semantic ref (
button:Login) 를 Gherkin 본문에 포함 - ❌
K.xxxKey같은 코드 식별자를 Gherkin 에 포함 - ❌ 1 Scenario 에
When이 5개 이상 (책임 과다) - ❌ 폼 필드 3개 이상을 개별
When/And로 나열 (Given data table + 단일 When 사용) - ❌
TODO주석 잔존 상태 lock - ❌ 초안 경고 주석 잔존 상태 lock
- ❌ 서로 다른
Background가 필요한 Scenario 를 한.feature에 섞기 (배치가 불가능해짐 — §5.1) - ❌ §5.1 의
@isolated조건에 해당하는 시나리오를 배치에 넣기 (로그아웃·결제·@journey·콜드스타트) - ❌ 배치를 핑계로 한 Scenario 에 여러 행위를 몰아넣기 (§5 는 그대로 유효)
참고#
- 원전:
cc-flutter/skills/bdd-testing/SKILL.md - Step 규약:
cc-flutter/rules/bdd-test-patterns.md - 공유 step 사전:
cc-flutter/agents/bdd-step-reuse-agent.md가 관리