LogoSkills

bdd:refactor-steps

Analyze and refactor BDD Gherkin step reusability.

ํ•ญ๋ชฉ๋‚ด์šฉ
Invoke/bdd:refactor-steps
Aliases/bdd:refactor, /bdd:step-audit
Categorytest-quality
Complexitymoderate

/bdd:refactor-steps โ€” ํ…Œ์ŠคํŠธ ๋ฌธ์žฅ ์ค‘๋ณต ์ •๋ฆฌ ๋„์šฐ๋ฏธ#

ํ•œ๋งˆ๋””๋กœ#

์—ฌ๋Ÿฌ ํ…Œ์ŠคํŠธ์— ํฉ์–ด์ง„ ๊ฐ™์€ ๋œป์˜ ๋ฌธ์žฅ์„ ํ•˜๋‚˜์˜ ํ‘œ์ค€ ๋ฌธ์žฅ์œผ๋กœ ์ •๋ฆฌํ•ด ์ฃผ๋Š” ๋ช…๋ น์ž…๋‹ˆ๋‹ค. ํšŒ์‚ฌ ๋ฌธ์„œ๋งˆ๋‹ค ์ œ๊ฐ๊ฐ ์“ฐ๋˜ ํ‘œํ˜„("ํ™•์ธ ๋ฐ”๋ž๋‹ˆ๋‹ค" / "ํ™•์ธ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค" / "์ฒดํฌ ์š”๋ง")์„ ํ•˜๋‚˜์˜ ๊ณต์‹ ํ‘œํ˜„์œผ๋กœ ํ†ต์ผํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์•„์š”.

๋ˆ„๊ฐ€ยท์–ธ์ œ ์“ฐ๋‚˜์š”#

  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ •๋ฆฌยท์œ ์ง€๋ณด์ˆ˜ํ•  ๋•Œ
  • ์ƒˆ ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์ „์—, ์ด๋ฏธ ์žˆ๋Š” ๋ฌธ์žฅ์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ ๊ฒ€ํ•  ๋•Œ
  • ๊ฐ™์€ ํ…Œ์ŠคํŠธ ๋ฌธ์žฅ์ด ์—ฌ๊ธฐ์ €๊ธฐ ์ค‘๋ณต๋œ ๊ฒƒ ๊ฐ™์„ ๋•Œ
  • ์ƒˆ ํ…Œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” /bdd:generate ๋ช…๋ น์„ ๋Œ๋ฆฌ๊ธฐ ์ „ ์‚ฌ์ „ ์ ๊ฒ€์šฉ์œผ๋กœ

๋ฌด์—‡์„ ํ•ด์ฃผ๋‚˜์š”#

  • ํ”„๋กœ์ ํŠธ ์ „์ฒด์— ํฉ์–ด์ง„ ํ…Œ์ŠคํŠธ ๋ฌธ์žฅ(step ํŒŒ์ผ)์„ ๋ชจ์•„ ์ค‘๋ณตยท์œ ์‚ฌ ํ‘œํ˜„์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค.
  • ์–ด๋–ค ๋ฌธ์žฅ์ด ๋ช‡ ๋ฒˆ ์ค‘๋ณต๋๋Š”์ง€, ํ‘œ์ค€์œผ๋กœ ๋ฐ”๊ฟ€ ๋Œ€์ƒ์€ ๋ฌด์—‡์ธ์ง€ ์ •๋ฆฌํ•œ ์žฌ์‚ฌ์šฉ์„ฑ ๋ณด๊ณ ์„œ๋ฅผ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.
  • --fix ๋ชจ๋“œ์—์„œ๋Š” .feature ํŒŒ์ผ์˜ ๋ฌธ์žฅ์„ ํ‘œ์ค€ ํ‘œํ˜„์œผ๋กœ ๋ฐ”๊พธ๊ณ , ์ค‘๋ณต๋œ step ํŒŒ์ผ์„ ์ •๋ฆฌํ•œ ๋’ค, ํ…Œ์ŠคํŠธ๊ฐ€ ๊ทธ๋Œ€๋กœ ์ž˜ ํ†ต๊ณผํ•˜๋Š”์ง€๊นŒ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ์“ฐ๋‚˜์š”#

/bdd:refactor-steps                          # ์ „์ฒด ํ”„๋กœ์ ํŠธ ๋ถ„์„
/bdd:refactor-steps store                    # ํŠน์ • feature๋งŒ ๋ถ„์„
/bdd:refactor-steps --fix                    # ์ž๋™ ์ˆ˜์ • ๋ชจ๋“œ
/bdd:refactor-steps --report                 # ๋ณด๊ณ ์„œ๋งŒ ์ถœ๋ ฅ
/bdd:refactor-steps --scope console          # ์ฝ˜์†” feature๋งŒ
  • ๋’ค์— store ๊ฐ™์€ ์ด๋ฆ„์„ ๋ถ™์ด๋ฉด ๊ทธ ๊ธฐ๋Šฅ ํ•˜๋‚˜๋งŒ ๋ด…๋‹ˆ๋‹ค (์ƒ๋žตํ•˜๋ฉด ์ „์ฒด).
  • --report๋Š” ๊ณ ์น˜์ง€ ์•Š๊ณ  ๋ณด๊ณ ์„œ๋งŒ, --fix๋Š” ๋ถ„์„ ํ›„ ์‹ค์ œ ์ˆ˜์ •๊นŒ์ง€, --dry-run์€ ๋ฐ”๊ฟ€ ๋‚ด์šฉ์„ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋งŒ ํ•ฉ๋‹ˆ๋‹ค.
  • --scope๋กœ ๋ฒ”์œ„๋ฅผ ์ขํž ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (application, console, common).

์•ˆ์—์„œ ๋ฌด์Šจ ์ผ์ด ๋ฒŒ์–ด์ง€๋‚˜์š”#

  1. ๋ชจ์œผ๊ธฐ โ€” ํ”„๋กœ์ ํŠธ ์ „์ฒด์˜ ํ…Œ์ŠคํŠธ ๋ฌธ์žฅ ํŒŒ์ผ์„ ๊ธ์–ด๋ชจ์•„ ๋ชฉ๋ก(์ธ๋ฒคํ† ๋ฆฌ)์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  2. ์ค‘๋ณต ์ฐพ๊ธฐ โ€” ์™„์ „ํžˆ ๋˜‘๊ฐ™์€ ๋ฌธ์žฅ, ์‚ด์ง๋งŒ ๋‹ค๋ฅธ ๋น„์Šทํ•œ ๋ฌธ์žฅ, "๋ฒ„ํŠผ ์ด๋ฆ„๋งŒ ๋‹ค๋ฅธ" ๋ฌธ์žฅ ๋“ฑ์„ ๋ถ„๋ฅ˜ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ณด๊ณ ์„œ ๋งŒ๋“ค๊ธฐ โ€” ์ค‘๋ณต ํšŸ์ˆ˜, ํ‘œ์ค€ํ™” ๋Œ€์ƒ, ํ•˜๋‚˜๋กœ ํ•ฉ์น  ํ›„๋ณด๋ฅผ ํ‘œ๋กœ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  4. ์ž๋™ ์ˆ˜์ •(--fix) โ€” ํ‘œ์ค€ ํ‘œํ˜„์œผ๋กœ ๋ฌธ์žฅ์„ ๋ฐ”๊พธ๊ณ , ์ค‘๋ณต ํŒŒ์ผ์„ ๊ณต์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์˜ฎ๊ธด ๋’ค ์ •๋ฆฌํ•˜๊ณ , ๋นŒ๋“œ์™€ ํ…Œ์ŠคํŠธ๋ฅผ ๋‹ค์‹œ ๋Œ๋ ค ์ด์ƒ ์—†๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

โš™๏ธ ์ƒ์„ธ ์˜ต์…˜ยท์‹คํ–‰ ๋ช…์„ธ (๊ฐœ๋ฐœ์ž / AI ์—์ด์ „ํŠธ์šฉ)

Triggers#

  • BDD ํ…Œ์ŠคํŠธ ์œ ์ง€๋ณด์ˆ˜ ์‹œ
  • ์ƒˆ feature ์ž‘์„ฑ ์ „ ๊ธฐ์กด step ์žฌ์‚ฌ์šฉ ํ™•์ธ
  • step ์ค‘๋ณต์ด ์˜์‹ฌ๋  ๋•Œ
  • /bdd:generate ์‹คํ–‰ ์ „ ์‚ฌ์ „ ์ ๊ฒ€

์‚ฌ์šฉ๋ฒ•#

/bdd:refactor-steps                          # ์ „์ฒด ํ”„๋กœ์ ํŠธ ๋ถ„์„
/bdd:refactor-steps store                    # ํŠน์ • feature๋งŒ ๋ถ„์„
/bdd:refactor-steps --fix                    # ์ž๋™ ์ˆ˜์ • ๋ชจ๋“œ
/bdd:refactor-steps --report                 # ๋ณด๊ณ ์„œ๋งŒ ์ถœ๋ ฅ
/bdd:refactor-steps --scope console          # ์ฝ˜์†” feature๋งŒ

Parameters#

ParameterRequiredDescriptionExample
feature_nameNoํŠน์ • feature ๋ถ„์„ (์ƒ๋žต ์‹œ ์ „์ฒด)store
--fixNo๋ถ„์„ + ์ž๋™ ์ˆ˜์ •true
--reportNo๋ถ„์„ ๋ณด๊ณ ์„œ๋งŒ ์ถœ๋ ฅtrue
--scopeNofeature ๋ฒ”์œ„ ์ œํ•œapplication, console, common
--dry-runNo๋ณ€๊ฒฝ ๋‚ด์šฉ ๋ฏธ๋ฆฌ๋ณด๊ธฐ (์ˆ˜์ • ์—†์Œ)true

์‹คํ–‰ ํ๋ฆ„#

Phase 1: Step ์ธ๋ฒคํ† ๋ฆฌ ์ˆ˜์ง‘#

ํ”„๋กœ์ ํŠธ ์ „์ฒด์˜ step ํŒŒ์ผ์„ ์Šค์บ”ํ•˜์—ฌ ์ธ๋ฒคํ† ๋ฆฌ๋ฅผ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค.

# 1. ๋ชจ๋“  step ํŒŒ์ผ ์ˆ˜์ง‘
find . -path  " */test/src/bdd/step/*.dart "   -exec basename {} \;

# 2. ์ค‘๋ณต ํŒŒ์ผ๋ช… ์ง‘๊ณ„
find . -path  " */test/src/bdd/step/*.dart "   -exec basename {} \; | sort | uniq -c | sort -rn

# 3. feature๋ณ„ step ์ˆ˜ ์ง‘๊ณ„
for dir in feature/*/; do
  count=$(find  " $dir "   -path  " */test/src/bdd/step/*.dart "   | wc -l)
  echo  " $count $dir " 
 done | sort -rn

์ˆ˜์ง‘ ํ•ญ๋ชฉ:

  • step ํŒŒ์ผ๋ช… (= step ํ‘œํ˜„)
  • step ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜
  • ์‚ฌ์šฉํ•˜๋Š” feature ๋ชฉ๋ก
  • ๊ตฌํ˜„ ์ƒํƒœ (UnimplementedError / no-op / ์‹ค๊ตฌํ˜„)

Phase 2: ์ค‘๋ณต ๋ฐ ์œ ์‚ฌ step ๋ถ„์„#

2.1 ์ •ํ™•ํžˆ ๋™์ผํ•œ step (Exact Duplicates)

๋™์ผํ•œ ํŒŒ์ผ๋ช…์ด 2๊ฐœ ์ด์ƒ์˜ feature์— ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ:

the_error_message_should_be_displayed.dart  โ†’ 33๊ฐœ feature
the_loading_indicator_should_be_displayed.dart โ†’ 27๊ฐœ feature
the_search_results_should_be_displayed.dart โ†’ 16๊ฐœ feature

2.2 ์œ ์‚ฌํ•œ step (Near Duplicates)

Canonical Step Dictionary ๊ธฐ์ค€์œผ๋กœ ์ •๊ทœํ™” ๊ฐ€๋Šฅํ•œ ๋ณ€ํ˜•:

ํ˜„์žฌ ํ‘œํ˜„ํ‘œ์ค€ ํ‘œํ˜„๋ณ€ํ™˜ ๊ทœ์น™
the X is loadedthe X has loadedtense ํ†ต์ผ
the X is in loading statethe X is loading์ถ•์•ฝ
an error message should be displayedthe error message should be displayed๊ด€์‚ฌ ํ†ต์ผ
the book detail screen should be displayedthe book detail page should be displayedscreenโ†’page
I click the X buttonI tap the X buttonclickโ†’tap

2.3 ํŒŒ๋ผ๋ฏธํ„ฐํ™” ๊ฐ€๋Šฅํ•œ step

๊ตฌ์ฒด์ ์ธ ์ด๋ฆ„๋งŒ ๋‹ค๋ฅด๊ณ  ๊ตฌ์กฐ๊ฐ€ ๋™์ผํ•œ step:

# ํ˜„์žฌ: ๊ฐ๊ฐ ๋ณ„๋„ step
i_tap_the_search_button.dart    (14๊ฐœ)
i_tap_the_save_button.dart      (9๊ฐœ)
i_tap_the_delete_button.dart    (7๊ฐœ)
i_tap_the_submit_button.dart    (4๊ฐœ)

# ๊ฐœ์„ : ํ•˜๋‚˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐํ™”๋œ step
# Gherkin: I tap the { ' search ' } button
# Step: iTapTheButton(WidgetTester tester, String buttonName)

Phase 3: ๋ณด๊ณ ์„œ ์ƒ์„ฑ (--report)#

## BDD Step ์žฌ์‚ฌ์šฉ์„ฑ ๋ณด๊ณ ์„œ

### ์š”์•ฝ
- ์ด step ํŒŒ์ผ: {N}๊ฐœ
- ๊ณ ์œ  step: {N}๊ฐœ
- ์ค‘๋ณต step: {N}๊ฐœ ({%}%)
- ์ œ๊ฑฐ ๊ฐ€๋Šฅ ํŒŒ์ผ: {N}๊ฐœ

### Top 20 ์ค‘๋ณต step
| Step | ์ค‘๋ณต ํšŸ์ˆ˜ | ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ›„๋ณด |
|------|:---------:|:------------------:|
| ... | ... | Yes/No |

### ํ‘œํ˜„ ์ •๊ทœํ™” ๋Œ€์ƒ
| ํ˜„์žฌ | ํ‘œ์ค€ | ์˜ํ–ฅ feature ์ˆ˜ |
|------|------|:---------------:|
| ... | ... | ... |

### ํŒŒ๋ผ๋ฏธํ„ฐํ™” ํ›„๋ณด
| ํŒจํ„ด | ํ˜„์žฌ ๊ฐœ๋ณ„ step ์ˆ˜ | ํ†ตํ•ฉ ์‹œ |
|------|:-----------------:|:------:|
| ... | ... | 1๊ฐœ |

Phase 4: ์ž๋™ ์ˆ˜์ • (--fix)#

4.1 .feature ํŒŒ์ผ ์ •๊ทœํ™”

Canonical Step Dictionary์— ๋”ฐ๋ผ step ํ…์ŠคํŠธ๋ฅผ ํ‘œ์ค€ํ™”:

# Before
Given the store is loaded
Then the error message should be displayed

# After
Given the store has loaded
Then the error message should be displayed  # (์ด๋ฏธ ํ‘œ์ค€)

4.2 ์ค‘๋ณต step ํŒŒ์ผ ์ •๋ฆฌ

๊ณต์œ  step๊ณผ ๋™์ผํ•œ ๊ตฌํ˜„์„ ๊ฐ€์ง„ ๋กœ์ปฌ step ํŒŒ์ผ ์ œ๊ฑฐ (externalSteps ์„ค์ • ํ›„):

  1. ๊ณต์œ  step ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— canonical step ์ถ”๊ฐ€
  2. ๊ฐ feature์˜ build.yaml์— externalSteps ์ถ”๊ฐ€
  3. ๋กœ์ปฌ ์ค‘๋ณต step ํŒŒ์ผ ์‚ญ์ œ
  4. melos run build ์‹คํ–‰ํ•˜์—ฌ ์ƒ์„ฑ ์ฝ”๋“œ ๊ฐฑ์‹ 
  5. melos run test:bdd ์‹คํ–‰ํ•˜์—ฌ ํ…Œ์ŠคํŠธ ํ†ต๊ณผ ํ™•์ธ

4.3 build_runner ์žฌ์ƒ์„ฑ

melos run build:clean  & &   melos run build
melos run test:bdd  # ๋˜๋Š” test:bdd:select

Canonical Step Dictionary#

AI Agent๊ฐ€ .feature ํŒŒ์ผ ์ž‘์„ฑ ์‹œ ๋ฐ˜๋“œ์‹œ ์ฐธ์กฐํ•ด์•ผ ํ•˜๋Š” ํ‘œ์ค€ step ํ‘œํ˜„์ž…๋‹ˆ๋‹ค.

Given (Setup) Steps#

ํ‘œ์ค€ ํ‘œํ˜„์šฉ๋„ํŒŒ๋ผ๋ฏธํ„ฐ
I am on the {page} pageํŽ˜์ด์ง€ ์„ค์ •{page}: snake_case
the {page} has loaded๋ฐ์ดํ„ฐ ๋กœ๋“œ ์™„๋ฃŒ{page}
the {page} is loading๋กœ๋”ฉ ์ค‘ ์ƒํƒœ{page}
the {page} is initialized์ดˆ๊ธฐํ™” ์™„๋ฃŒ{page}
the {page} has an error์—๋Ÿฌ ์ƒํƒœ{page}
the {page} is empty๋นˆ ์ƒํƒœ{page}

๊ธˆ์ง€ ๋ณ€ํ˜•:

  • the X is loaded โ†’ the X has loaded
  • the X is in loading state โ†’ the X is loading
  • the X has been initialized โ†’ the X is initialized

When (Action) Steps โ€” ๋ฒ”์šฉ Key ๊ธฐ๋ฐ˜#

ํ‘œ์ค€ ํ‘œํ˜„์šฉ๋„ํŒŒ๋ผ๋ฏธํ„ฐ๊ณต์œ  step
I tap the {'widget_key'} widget๋ชจ๋“  ์œ„์ ฏ ํƒญWidget KeyYes
I tap the {'text'} textํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ํƒญํ™”๋ฉด ํ…์ŠคํŠธYes
I enter {'value'} in the {'key'} widget๋ชจ๋“  ์ž…๋ ฅ๊ฐ’ + KeyYes
I wait for {'N'} seconds๋Œ€๊ธฐ์ดˆYes
I scroll down์Šคํฌ๋กค-No
I upload a fileํŒŒ์ผ ์—…๋กœ๋“œ-No

๊ธˆ์ง€ ๋ณ€ํ˜• (๋„๋ฉ”์ธ ํŠนํ™” step โ†’ ๋ฒ”์šฉ step ์‚ฌ์šฉ):

  • I tap the search button โ†’ I tap the {'search_button'} widget
  • I tap the save button โ†’ I tap the {'save_button'} widget
  • I select a book filter โ†’ I tap the {'book_filter'} widget
  • I enter a search keyword โ†’ I enter {'๊ฒ€์ƒ‰์–ด'} in the {'search_field'} widget
  • I confirm deletion โ†’ I tap the {'confirm_delete'} widget

Then (Assertion) Steps โ€” ๋ฒ”์šฉ Key ๊ธฐ๋ฐ˜#

ํ‘œ์ค€ ํ‘œํ˜„์šฉ๋„ํŒŒ๋ผ๋ฏธํ„ฐ๊ณต์œ  step
the {'widget_key'} widget should be displayed๋ชจ๋“  ์œ„์ ฏ ํ‘œ์‹œ ํ™•์ธWidget KeyYes
the {'text'} text should be displayedํ…์ŠคํŠธ ํ‘œ์‹œ ํ™•์ธํ™”๋ฉด ํ…์ŠคํŠธYes

๊ธˆ์ง€ ๋ณ€ํ˜• (๋„๋ฉ”์ธ ํŠนํ™” โ†’ ๋ฒ”์šฉ ์‚ฌ์šฉ):

  • should be visible โ†’ should be displayed (disabled/enabled๊ณผ ๊ตฌ๋ถ„)
  • should be shown โ†’ should be displayed
  • the X screen should be displayed โ†’ the X page should be displayed
  • an error message should be displayed โ†’ the error message should be displayed

๊ณต์œ  Step ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ตฌ์กฐ (co_test_gen ํ†ตํ•ฉ)#

๊ณต์œ  step์€ test_driver (๋˜๋Š” co_test_gen) ํŒจํ‚ค์ง€์˜ shared_step/ ๋””๋ ‰ํ† ๋ฆฌ์— ์œ„์น˜ํ•ฉ๋‹ˆ๋‹ค.

package/test_driver/
โ”œโ”€โ”€ lib/
โ”‚   โ”œโ”€โ”€ test_driver.dart          # ๊ธฐ์กด Driver/Key/Step export
โ”‚   โ”œโ”€โ”€ shared_steps.dart         # โ˜… ๊ณต์œ  step barrel export
โ”‚   โ””โ”€โ”€ src/
โ”‚       โ”œโ”€โ”€ driver/               # TestDriver ์ถ”์ƒํ™”
โ”‚       โ”œโ”€โ”€ key/                  # Widget Key ์ƒ์ˆ˜ (K ํด๋ž˜์Šค)
โ”‚       โ”œโ”€โ”€ step/                 # ๋„๋ฉ”์ธ๋ณ„ Step ํด๋ž˜์Šค
โ”‚       โ””โ”€โ”€ shared_step/          # โ˜… BDD ํ˜ธํ™˜ ๊ณต์œ  step ํ•จ์ˆ˜
โ”‚           โ”œโ”€โ”€ then/
โ”‚           โ”‚   โ”œโ”€โ”€ the_error_message_should_be_displayed.dart
โ”‚           โ”‚   โ”œโ”€โ”€ the_loading_indicator_should_be_displayed.dart
โ”‚           โ”‚   โ””โ”€โ”€ ... (11๊ฐœ)
โ”‚           โ””โ”€โ”€ when/
โ”‚               โ”œโ”€โ”€ i_tap_the_search_button.dart
โ”‚               โ”œโ”€โ”€ i_confirm_deletion.dart
โ”‚               โ””โ”€โ”€ ... (13๊ฐœ)
โ””โ”€โ”€ pubspec.yaml

build.yaml ์„ค์ • (co_test_gen ์‚ฌ์šฉ ์‹œ)#

co_test_gen|dual_test_gen:
  enabled: true
  generate_for:
    - test/src/bdd/*.feature
  options:
    stepFolder: step
    sharedSteps: true                                          # โ˜… ํ™œ์„ฑํ™”
    sharedStepsImport:  " package:test_driver/shared_steps.dart "   # โ˜… import ๊ฒฝ๋กœ
    sharedStepNames:                                           # โ˜… ๋งค์นญ ๋ชฉ๋ก
      - the_error_message_should_be_displayed
      - the_loading_indicator_should_be_displayed
      - the_success_message_should_be_displayed
      - the_search_results_should_be_displayed
      - i_enter_a_search_keyword
      - i_confirm_deletion
      - i_tap_the_next_page_button
      - i_tap_the_search_button

/bdd:generate์™€์˜ ์—ฐ๋™#

/bdd:generate ์‹คํ–‰ ์‹œ ์ž๋™์œผ๋กœ Canonical Step Dictionary๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค:

  1. ์ƒˆ step ์ž‘์„ฑ ์ „: ๊ธฐ์กด step ๋ชฉ๋ก ์Šค์บ”
  2. ์œ ์‚ฌ ํ‘œํ˜„ ๊ฐ์ง€: Dictionary์™€ ๋น„๊ตํ•˜์—ฌ ํ‘œ์ค€ ํ‘œํ˜„ ์ถ”์ฒœ
  3. ๊ณต์œ  step ์šฐ์„ : sharedStepNames์— ์ด๋ฏธ ์žˆ๋Š” step์€ ๋กœ์ปฌ ์ƒ์„ฑ ์Šคํ‚ต
  4. ๋ณด๊ณ : ์ƒˆ๋กœ ์ƒ์„ฑ๋œ step vs ์žฌ์‚ฌ์šฉ๋œ step ๋น„์œจ ํ‘œ์‹œ

๊ฒ€์ฆ#

# 1. step ์ค‘๋ณต ๊ฒ€์‚ฌ
find . -path  " */test/src/bdd/step/*.dart "   -exec basename {} \; | sort | uniq -c | sort -rn | head -20

# 2. build ํ™•์ธ
melos run build:clean  & &   melos run build

# 3. BDD ํ…Œ์ŠคํŠธ ์‹คํ–‰
melos run test:bdd

# 4. ์žฌ์‚ฌ์šฉ๋ฅ  ์ธก์ •
total=$(find . -path  " */test/src/bdd/step/*.dart "   | wc -l)
unique=$(find . -path  " */test/src/bdd/step/*.dart "   -exec basename {} \; | sort -u | wc -l)
echo  " ์žฌ์‚ฌ์šฉ๋ฅ : $(( (total - unique) * 100 / total ))% "

์ฐธ์กฐ#

  • .claude/rules/bdd-test-patterns.md โ€” BDD ํ…Œ์ŠคํŠธ ํŒจํ„ด ๊ทœ์น™
  • .claude/rules/patrol-bdd-conventions.md โ€” Patrol BDD ํ†ตํ•ฉ ๊ทœ์น™
  • cc-flutter-dev/commands/bdd/generate.md โ€” BDD ์ƒ์„ฑ ์ปค๋งจ๋“œ
  • docs/discovery-bdd-step-reusability.md โ€” Discovery ๋ถ„์„ ๋ณด๊ณ ์„œ