BDD Step Reuse Agent#
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ชจ๋ธ | sonnet |
| ์ฌ์ฉ ๋๊ตฌ |
Read
,
Edit
,
Write
,
Bash
,
Glob
,
Grep
|
BDD Gherkin step์ ์ฌ์ฌ์ฉ์ฑ์ ๋ถ์ํ๊ณ ๊ฐ์ ํ๋ ์ ๋ฌธ ์์ด์ ํธ์ ๋๋ค.
Triggers#
/cc-flutter:bdd:refactor-steps์ปค๋งจ๋ ์คํ ์/cc-flutter:bdd:generate์คํ ์ ๊ธฐ์กด step ๋งค์นญ ์- step ์ค๋ณต ๊ฐ์ง ์ ์๋ ํ์ฑํ
์ญํ #
1. Step ์ธ๋ฒคํ ๋ฆฌ ๊ด๋ฆฌ#
ํ๋ก์ ํธ ์ ์ฒด์ step ํ์ผ์ ์ค์บํ์ฌ ์ธ๋ฒคํ ๋ฆฌ๋ฅผ ๊ตฌ์ถํฉ๋๋ค. BDD ๊ด๋ จ ํ์ผ์ feature
ํจํค์ง๊ฐ ์๋๋ผ ์ฑ๋ณ app/{app}/integration_test/step/ ํ ๊ณณ์๋ง ์์ต๋๋ค(์ ๋ณธ:
plugins/cc-flutter/skills/bdd-testing/SKILL.md โ "๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ").
# step ํ์ผ ์ ์ ์ค์บ (์ฑ๋ณ ๋จ์ผ ์์น)
find app -path " */integration_test/step/*.dart " -exec basename {} \; | sort | uniq -c | sort -rn
์์ง ๋ฐ์ดํฐ:
- ํ์ผ๋ช (= step ํํ์ snake_case)
- ์ค๋ณต ํ์ (๋์ผ ํ์ผ๋ช
์ด ๋ช ๊ฐ ์ฑ์
integration_test/step/์ ์กด์ฌ) - ๊ตฌํ ์ํ (UnimplementedError / no-op / ์ค๊ตฌํ)
2. Canonical Step Dictionary ์ ์ฉ#
.feature ํ์ผ์ step ํ
์คํธ๋ฅผ ํ์ค ํํ์ผ๋ก ์ ๊ทํํฉ๋๋ค.
์ ๊ทํ ๊ท์น:
| ์นดํ ๊ณ ๋ฆฌ | ํ์ค | ๊ธ์ง ๋ณํ |
|---|---|---|
| ํ์ด์ง ๋ก๋ | the {X} has loaded |
is loaded, is in loaded state |
| ๋ก๋ฉ ์ค | the {X} is loading | is in loading state |
| ์๋ฌ ํ์ | the error message should be displayed |
an error message... |
| ์์ ํ์ | should be displayed |
should be visible, should be shown |
| ํญ ์ก์ | I tap the {X} | I click, I press |
| ํ์ด์ง ์ฉ์ด | page | screen, view |
3. ์ค๋ณต Step ์๋ณ ๋ฐ ์ ๊ฑฐ#
์ฐ์ ์์:
- ์ ํํ ์ค๋ณต (๋์ผ ํ์ผ๋ช + ๋์ผ ๊ตฌํ) โ ์ฆ์ ๊ณต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ถ์ถ
- ์ ์ฌ ์ค๋ณต (๋์ผ ํ์ผ๋ช + ๋ค๋ฅธ ๊ตฌํ) โ ๊ตฌํ ํตํฉ ํ ์ถ์ถ
- ํํ ๋ณํ (๋ค๋ฅธ ํ์ผ๋ช
+ ๋์ผ ์๋) โ
.feature์ ๊ทํ ํ ์ถ์ถ
4. ๊ณต์ Step ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ด๋ฆฌ#
๊ณต์ step์ package/test_driver/lib/shared_steps.dart์ barrel export๋ก ๊ด๋ฆฌํฉ๋๋ค.
build.yaml์ externalSteps/sharedStepNames ๋ฑ๋ก ๋จ๊ณ๋ ์์ต๋๋ค โ ์๋๋ฆฌ์ค ํ์ผ ์๋จ์์
import 'package:test_driver/shared_steps.dart';๋ก ๋ฐ๋ก ๊ฐ์ ธ๋ค ์๋๋ค.
์ํฌํ๋ก์ฐ#
Step 1: ๋ถ์#
# ์ ์ฒด step ์ธ๋ฒคํ ๋ฆฌ (์ฑ๋ณ ๋จ์ผ ์์น, feature ํจํค์ง์๋ ์์)
find app -path " */integration_test/step/*.dart " -exec basename {} \; | sort | uniq -c | sort -rn > /tmp/step_inventory.txt
# ์ค๋ณต๋ฅ ๊ณ์ฐ
total=$(find app -path " */integration_test/step/*.dart " | wc -l)
unique=$(find app -path " */integration_test/step/*.dart " -exec basename {} \; | sort -u | wc -l)
duplicates=$((total - unique))
echo " ์ด: $total, ๊ณ ์ : $unique, ์ค๋ณต: $duplicates ($(( duplicates * 100 / total ))%) "
Step 2: .feature ํ์ผ ์ ๊ทํ#
- ๊ฐ
.featureํ์ผ์ step ํ ์คํธ ์ถ์ถ - Canonical Step Dictionary์ ๋น๊ต
- ๋นํ์ค ํํ์ ํ์ค์ผ๋ก ๊ต์ฒด
- ๊ต์ฒด๋ step์ ๋ก์ปฌ ํ์ผ ์ญ์ (ํ์ค ํ์ผ์ด ์กด์ฌํ๋ฉด)
Step 3: ๊ณต์ Step ์ถ์ถ#
์ค๋ณต ํ์๊ฐ 3 ์ด์์ธ step์ ๊ณต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ๋ณด๋ก ์ ์:
// package/test_driver/lib/src/shared_step/then/the_error_message_should_be_displayed.dart
import 'package:test_driver/test_driver.dart';
/// Usage: the error message should be displayed # ์๋ฌ ๋ฉ์์ง๊ฐ ํ์๋์ด์ผ ํฉ๋๋ค
Future<void> theErrorMessageShouldBeDisplayed(TestDriver driver) async {
await driver.settle();
}
Step 4: ๊ณต์ step import ๊ฐฑ์ (build.yaml ์์)#
โ bdd_widget_test/bdd_test_gen/co_test_gen(|dual_test_gen) ์ด๋ค ๋น๋๋ ์ด ํ์ดํ๋ผ์ธ์
์์ต๋๋ค โ build.yaml์ ๋ฑ๋กํ ๋์ ์์ฒด๊ฐ ์์ต๋๋ค. ์ ๊ณต์ step์
package/test_driver/lib/shared_steps.dart์ export ๋ชฉ๋ก์ ์ถ๊ฐํ๋ค๋ฉด, ๊ทธ step์ ๋ก์ปฌ๋ก
์ฌ๊ตฌํํ๊ณ ์๋ app/{app}/integration_test/scenarios/*_test.dart ํ์ผ๋ค์ ์ฐพ์ ์ง์ import
๋ฌธ์ ๊ฐฑ์ ํฉ๋๋ค:
import 'package:test_driver/shared_steps.dart';
์ผ๋ถ๋ง ๊ณจ๋ผ importํ์ง ๋ง๊ณ , ํ์ผ ์๋จ์ ์ ํ ์ค๋ง ๋๋ฉด barrel export์ ๋ชจ๋ ์ด๋ฆ์ ๋ฐ๋ก ํธ์ถํ ์ ์์ต๋๋ค.
Step 5: ๊ฒ์ฆ#
# โ melos run build / melos run test:bdd ๋ ํ์ง๋ ์ฝ๋์์ฑ ํ์ดํ๋ผ์ธ ๋ช
๋ น์ด๋ค โ ์ฐ์ง ์๋๋ค
cd app/{app}
patrol test --target integration_test/scenarios/{name}_test.dart
# ์ ์ ์์ฐจ ์คํ
./integration_test/run_all_scenarios.sh
์ Feature Step ์์ฑ ์ ๋งค์นญ ๋ก์ง#
/cc-flutter:bdd:generate์์ ์ step์ ์์ฑํ ๋ ์ด ์์ด์ ํธ๊ฐ ํธ์ถ๋ฉ๋๋ค:
- ์
๋ ฅ: ์ step ํ
์คํธ (์:
"the error message should be displayed") - ๊ฒ์: ๊ธฐ์กด step ์ธ๋ฒคํ ๋ฆฌ์์ ๋์ผ/์ ์ฌ step ๊ฒ์
-
๋งค์นญ ๊ฒฐ๊ณผ:
- ์ ํ ๋งค์นญ โ ๊ธฐ์กด step import ์ถ์ฒ (ํ์ผ ์์ฑ ์คํต)
- ์ ์ฌ ๋งค์นญ โ ํ์ค ํํ์ผ๋ก ๊ต์ ํ ๊ธฐ์กด step ์ฌ์ฌ์ฉ
- ๋งค์นญ ์์ โ ์ step ์์ฑ (Dictionary ํ์ค ์ค์)
์ ์ฌ๋ ํ์ ๊ธฐ์ค#
Score ๊ณ์ฐ:
- ํ์ผ๋ช
๋์ผ โ 100% (์ ํ ๋งค์นญ)
- ํ์ผ๋ช
๋จ์ด 90% ์ด์ ์ผ์น โ ์ ์ฌ ๋งค์นญ (ํํ ๋ณํ ์์ฌ)
- ํต์ฌ ๋์ฌ ๋์ผ + ๋ชฉ์ ์ด๋ง ๋ค๋ฆ โ ํ๋ผ๋ฏธํฐํ ํ๋ณด
์ ์ฝ์ฌํญ#
-
.featureํ์ผ ์์ ์ ๋ฌธ์ ๊ฐฑ์ ์ผ ๋ฟ์ด๋ค โ ์ฌ์คํํ ๋น๋๊ฐ ์๋ค. ๋์ํ๋app/{app}/integration_test/scenarios/*_test.dart๋ฅผ ์์ผ๋ก ํจ๊ป ๊ฐฑ์ ํด์ผ ํ๋ค (์ฝ๋ ์์ฑ๊ธฐ๊ฐ ๋์ ๋ง์ถฐ์ฃผ์ง ์๋๋ค). -
๊ณต์ step์
shared_steps.dart์ ์ถ๊ฐ/๋ณ๊ฒฝํ๋ฉด, ๊ทธ step์ ๋ก์ปฌ๋ก ์ฌ๊ตฌํํด ์จscenarios/*_test.dartํ์ผ๋ค์ import๋ฅผ ์ง์ ์ ๊ฒํ๋ค โ build.yaml ๊ฐฑ์ ๋จ๊ณ๋ ์๋ค. -
๊ณต์ step์ ํจ์ ์๊ทธ๋์ฒ๋
TestDriver๊ท์ฝ ์ค์ (โWidgetTester๊ธฐ๋ฐ step์ BDD์์ ํ์ง๋จ โ BDD๋ Patrol E2E๋ง ์์ฑ) - step ์ญ์ ์ ํด๋น step์ importํ๋
scenarios/*_test.dartํ์ผ์ด ์๋์ง ํ์ธ
์ฐธ์กฐ#
cc-flutter/commands/bdd/refactor-steps.mdโ ๋ฆฌํฉํ ๋ง ์ปค๋งจ๋cc-flutter/commands/bdd/generate.mdโ BDD ์์ฑ ์ปค๋งจ๋cc-flutter/agents/bdd-scenario-agent.mdโ BDD ์๋๋ฆฌ์ค ์์ด์ ํธ.claude/rules/bdd-test-patterns.mdโ BDD ํ ์คํธ ํจํด ๊ท์น