@panicgit/android-test-pilot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/atp/analyze-app/SKILL.md +86 -0
- package/.claude/skills/atp/app-map/SKILL.md +36 -0
- package/.claude/skills/atp/check-logs/SKILL.md +77 -0
- package/.claude/skills/atp/run-test/SKILL.md +92 -0
- package/README.ko.md +241 -0
- package/README.md +241 -0
- package/lib/android.d.ts +96 -0
- package/lib/android.js +740 -0
- package/lib/android.js.map +1 -0
- package/lib/image-utils.d.ts +28 -0
- package/lib/image-utils.js +156 -0
- package/lib/image-utils.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +90 -0
- package/lib/index.js.map +1 -0
- package/lib/ios.d.ts +54 -0
- package/lib/ios.js +241 -0
- package/lib/ios.js.map +1 -0
- package/lib/iphone-simulator.d.ts +34 -0
- package/lib/iphone-simulator.js +227 -0
- package/lib/iphone-simulator.js.map +1 -0
- package/lib/logger.d.ts +2 -0
- package/lib/logger.js +23 -0
- package/lib/logger.js.map +1 -0
- package/lib/mobile-device.d.ts +25 -0
- package/lib/mobile-device.js +141 -0
- package/lib/mobile-device.js.map +1 -0
- package/lib/mobilecli.d.ts +32 -0
- package/lib/mobilecli.js +113 -0
- package/lib/mobilecli.js.map +1 -0
- package/lib/png.d.ts +9 -0
- package/lib/png.js +20 -0
- package/lib/png.js.map +1 -0
- package/lib/robot.d.ts +116 -0
- package/lib/robot.js +10 -0
- package/lib/robot.js.map +1 -0
- package/lib/server.d.ts +3 -0
- package/lib/server.js +692 -0
- package/lib/server.js.map +1 -0
- package/lib/tiers/abstract-tier.d.ts +48 -0
- package/lib/tiers/abstract-tier.js +35 -0
- package/lib/tiers/abstract-tier.js.map +1 -0
- package/lib/tiers/screenshot-tier.d.ts +19 -0
- package/lib/tiers/screenshot-tier.js +53 -0
- package/lib/tiers/screenshot-tier.js.map +1 -0
- package/lib/tiers/text-tier.d.ts +20 -0
- package/lib/tiers/text-tier.js +138 -0
- package/lib/tiers/text-tier.js.map +1 -0
- package/lib/tiers/tier-runner.d.ts +27 -0
- package/lib/tiers/tier-runner.js +91 -0
- package/lib/tiers/tier-runner.js.map +1 -0
- package/lib/tiers/types.d.ts +100 -0
- package/lib/tiers/types.js +12 -0
- package/lib/tiers/types.js.map +1 -0
- package/lib/tiers/uiautomator-tier.d.ts +16 -0
- package/lib/tiers/uiautomator-tier.js +91 -0
- package/lib/tiers/uiautomator-tier.js.map +1 -0
- package/lib/utils.d.ts +4 -0
- package/lib/utils.js +81 -0
- package/lib/utils.js.map +1 -0
- package/lib/webdriver-agent.d.ts +45 -0
- package/lib/webdriver-agent.js +400 -0
- package/lib/webdriver-agent.js.map +1 -0
- package/package.json +50 -0
- package/templates/scenario.md +49 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: analyze-app
|
|
3
|
+
description: "Android app static analysis — build navigation map, API scenarios, and View state map"
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
user-invocable: true
|
|
6
|
+
allowed-tools: Read Grep Glob Bash Write
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Step 0: Android App Static Analysis
|
|
10
|
+
|
|
11
|
+
Analyze the Android source code in the current project to build a complete app map.
|
|
12
|
+
Run all three analyses in order and save results to `.claude/app-map/`.
|
|
13
|
+
|
|
14
|
+
## 0-A. Screen Navigation Flow
|
|
15
|
+
|
|
16
|
+
Analyze:
|
|
17
|
+
- `AndroidManifest.xml` for Activity declarations
|
|
18
|
+
- Source code for `startActivity()`, `startActivityForResult()` calls
|
|
19
|
+
- `nav_graph.xml`, `navigation/*.xml` for Fragment transitions
|
|
20
|
+
- `Intent` creation patterns
|
|
21
|
+
|
|
22
|
+
Save to: `.claude/app-map/navigation_map.mermaid`
|
|
23
|
+
Format: Mermaid flowchart showing Activity/Fragment transition relationships.
|
|
24
|
+
|
|
25
|
+
## 0-B. API Connections & Response Scenarios
|
|
26
|
+
|
|
27
|
+
Analyze:
|
|
28
|
+
- Retrofit interfaces with `@GET`, `@POST`, `@PUT`, `@DELETE` annotations
|
|
29
|
+
- ViewModel/Repository call sites for each API
|
|
30
|
+
- Success (`onSuccess`) and error (`onError`) branches
|
|
31
|
+
|
|
32
|
+
Save to: `.claude/app-map/api_scenarios.json`
|
|
33
|
+
Format:
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"apis": [
|
|
37
|
+
{
|
|
38
|
+
"endpoint": "GET /api/users",
|
|
39
|
+
"interfaceFile": "UserApi.kt:15",
|
|
40
|
+
"callers": [
|
|
41
|
+
{
|
|
42
|
+
"file": "UserViewModel.kt:42",
|
|
43
|
+
"successHandler": "UserViewModel.kt:45-50",
|
|
44
|
+
"errorHandler": "UserViewModel.kt:51-55"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 0-C. View State Mapping
|
|
53
|
+
|
|
54
|
+
Analyze:
|
|
55
|
+
- `View.VISIBLE`, `View.GONE`, `View.INVISIBLE` conditions
|
|
56
|
+
- `LiveData.observe()`, `StateFlow.collect()` call sites
|
|
57
|
+
- DataBinding expressions (`@{viewModel.isLoading}`)
|
|
58
|
+
- RecyclerView adapter data binding
|
|
59
|
+
|
|
60
|
+
Save to: `.claude/app-map/view_state_map.json`
|
|
61
|
+
Format:
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"screens": [
|
|
65
|
+
{
|
|
66
|
+
"name": "LoginActivity",
|
|
67
|
+
"file": "LoginActivity.kt",
|
|
68
|
+
"states": [
|
|
69
|
+
{
|
|
70
|
+
"viewId": "btn_login",
|
|
71
|
+
"visibilityCondition": "isFormValid && !isLoading",
|
|
72
|
+
"dataSource": "LoginViewModel.loginFormState",
|
|
73
|
+
"sourceFile": "LoginActivity.kt:67"
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Execution Rules
|
|
82
|
+
|
|
83
|
+
1. Create `.claude/app-map/` directory if it doesn't exist.
|
|
84
|
+
2. Run 0-A, 0-B, 0-C in order.
|
|
85
|
+
3. Save each output file upon completion.
|
|
86
|
+
4. Print a summary of findings after all analyses complete.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: app-map
|
|
3
|
+
description: "View Step 0 static analysis results summary"
|
|
4
|
+
user-invocable: true
|
|
5
|
+
allowed-tools: Read Glob
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# App Map Summary
|
|
9
|
+
|
|
10
|
+
Read and summarize the Step 0 analysis artifacts in `.claude/app-map/`.
|
|
11
|
+
|
|
12
|
+
## Check for artifacts
|
|
13
|
+
|
|
14
|
+
```!
|
|
15
|
+
ls -la .claude/app-map/ 2>/dev/null || echo "NO_ARTIFACTS"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
If no artifacts found:
|
|
19
|
+
> No analysis results yet. Run `/atp:analyze-app` to generate them.
|
|
20
|
+
|
|
21
|
+
If artifacts exist, read each file and summarize:
|
|
22
|
+
|
|
23
|
+
### Navigation Map
|
|
24
|
+
- Total screen count
|
|
25
|
+
- Key entry points
|
|
26
|
+
- Screen transition relationships
|
|
27
|
+
|
|
28
|
+
### API Scenarios
|
|
29
|
+
- Total API count
|
|
30
|
+
- Endpoint list
|
|
31
|
+
- Success/error branch coverage
|
|
32
|
+
|
|
33
|
+
### View State Map
|
|
34
|
+
- Total screen count
|
|
35
|
+
- Number of Views with dynamic state
|
|
36
|
+
- Data source types (LiveData, StateFlow, DataBinding)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: check-logs
|
|
3
|
+
description: "Check and augment logcat log coverage based on Step 0 analysis results"
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
user-invocable: true
|
|
6
|
+
allowed-tools: Read Grep Glob Bash Write Edit
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Step 1: Log Coverage Check & Augmentation
|
|
10
|
+
|
|
11
|
+
Check if the source code has sufficient logcat logs for device testing (Step 2),
|
|
12
|
+
and offer to add missing logs.
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
Verify these files exist:
|
|
17
|
+
- `.claude/app-map/navigation_map.mermaid`
|
|
18
|
+
- `.claude/app-map/api_scenarios.json`
|
|
19
|
+
- `.claude/app-map/view_state_map.json`
|
|
20
|
+
|
|
21
|
+
If any are missing, stop with:
|
|
22
|
+
> Step 0 artifacts not found. Run `/atp:analyze-app` first.
|
|
23
|
+
|
|
24
|
+
## 1-A. Screen Entry/Transition Logs
|
|
25
|
+
|
|
26
|
+
Check:
|
|
27
|
+
- Whether a BaseActivity/BaseFragment exists
|
|
28
|
+
- Whether each Activity/Fragment has a screen entry log in `onCreate()` or `onResume()`
|
|
29
|
+
|
|
30
|
+
Expected log format:
|
|
31
|
+
```kotlin
|
|
32
|
+
Log.d("ATP_SCREEN", "enter: ${this::class.simpleName}")
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Report any screens missing this log.
|
|
36
|
+
|
|
37
|
+
## 1-B. View State (renderState) Logs
|
|
38
|
+
|
|
39
|
+
Using `.claude/app-map/view_state_map.json`, check each screen:
|
|
40
|
+
- Whether visibility condition changes are logged
|
|
41
|
+
|
|
42
|
+
Expected log format:
|
|
43
|
+
```kotlin
|
|
44
|
+
Log.d("ATP_RENDER", "renderState: screen=${screenName}, ${key}=${value}, ...")
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Report any View state changes missing this log.
|
|
48
|
+
|
|
49
|
+
## 1-C. API Response Logs
|
|
50
|
+
|
|
51
|
+
Using `.claude/app-map/api_scenarios.json`, check each API call site:
|
|
52
|
+
- Whether API responses are logged at the response handler
|
|
53
|
+
|
|
54
|
+
Expected log format:
|
|
55
|
+
```kotlin
|
|
56
|
+
Log.d("ATP_API", "apiResponse: endpoint=${endpoint}, status=${status}, bodyLength=${responseBody.length}")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Security note**: Avoid logging full response bodies (`body=${responseBody}`) as they may contain PII, authentication tokens, or other sensitive data. Log `bodyLength` instead, or redact sensitive fields before logging.
|
|
60
|
+
|
|
61
|
+
Report any API call sites missing this log.
|
|
62
|
+
|
|
63
|
+
## Workflow
|
|
64
|
+
|
|
65
|
+
1. Run 1-A, 1-B, 1-C analysis and report all gaps.
|
|
66
|
+
2. For each gap, ask the developer: "Add this log? (Y/N)"
|
|
67
|
+
3. Y → Insert the log directly into the source code.
|
|
68
|
+
4. N → Skip that item.
|
|
69
|
+
5. No automatic PR creation (developer's decision).
|
|
70
|
+
|
|
71
|
+
## Log Tag Convention
|
|
72
|
+
|
|
73
|
+
| Tag | Purpose | Format |
|
|
74
|
+
|-----|---------|--------|
|
|
75
|
+
| `ATP_SCREEN` | Screen entry/transition | `enter: {ClassName}` |
|
|
76
|
+
| `ATP_RENDER` | View state change | `renderState: screen={name}, {key}={value}, ...` |
|
|
77
|
+
| `ATP_API` | API response | `apiResponse: endpoint={endpoint}, status={status}, body={body}` |
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: run-test
|
|
3
|
+
description: "Run device test from a scenario file using 3-tier strategy (text → uiautomator → screenshot)"
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
user-invocable: true
|
|
6
|
+
allowed-tools: Read Grep Glob Bash
|
|
7
|
+
argument-hint: <scenario-file-path>
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Step 2: Device Test Execution
|
|
11
|
+
|
|
12
|
+
Read a scenario file and execute tests on a real device using the 3-tier strategy.
|
|
13
|
+
|
|
14
|
+
## Scenario File
|
|
15
|
+
|
|
16
|
+
$ARGUMENTS
|
|
17
|
+
|
|
18
|
+
If no scenario file path is provided, stop with:
|
|
19
|
+
> No scenario file specified. Usage: `/atp:run-test scenarios/login.md`
|
|
20
|
+
|
|
21
|
+
Read the scenario file and parse each test step.
|
|
22
|
+
|
|
23
|
+
## Prerequisites
|
|
24
|
+
|
|
25
|
+
Verify these files exist:
|
|
26
|
+
- `.claude/app-map/navigation_map.mermaid`
|
|
27
|
+
- `.claude/app-map/api_scenarios.json`
|
|
28
|
+
- `.claude/app-map/view_state_map.json`
|
|
29
|
+
|
|
30
|
+
If any are missing, stop with:
|
|
31
|
+
> Step 0/1 artifacts not found. Run `/atp:analyze-app` then `/atp:check-logs` first.
|
|
32
|
+
|
|
33
|
+
## Device Setup
|
|
34
|
+
|
|
35
|
+
1. Use MCP tool `mobile_list_available_devices` to find connected Android devices.
|
|
36
|
+
2. If no device found, stop with an error.
|
|
37
|
+
3. If multiple devices, use the first one (or ask the user to specify).
|
|
38
|
+
|
|
39
|
+
## Test Execution Strategy
|
|
40
|
+
|
|
41
|
+
Before starting, use `atp_logcat_start` to begin logcat streaming for the device.
|
|
42
|
+
|
|
43
|
+
For each test step in the scenario file, use the `atp_run_step` MCP tool:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
atp_run_step({
|
|
47
|
+
device: "<device-id>",
|
|
48
|
+
action: "<action from scenario step>",
|
|
49
|
+
verification: "<verification from scenario step>",
|
|
50
|
+
expectedLogcat: [
|
|
51
|
+
{ tag: "ATP_SCREEN", pattern: "enter: LoginActivity" }
|
|
52
|
+
],
|
|
53
|
+
tapTarget: { resourceId: "btn_login" }
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`atp_run_step` automatically handles the 3-tier fallback:
|
|
58
|
+
1. **Tier 1 (text)**: dumpsys + logcat pattern matching — fast, cheap
|
|
59
|
+
2. **Tier 2 (uiautomator)**: UI hierarchy search + resource-id tap — if Tier 1 can't determine
|
|
60
|
+
3. **Tier 3 (screenshot)**: visual capture — last resort, only if Tier 1+2 both fail
|
|
61
|
+
|
|
62
|
+
The tool returns a `TierResult` with: tier used, status (SUCCESS/FAIL/FALLBACK/ERROR), observation, and verification details.
|
|
63
|
+
|
|
64
|
+
### Manual Tier Tools (optional, for debugging)
|
|
65
|
+
|
|
66
|
+
Individual tier tools are also available for direct use:
|
|
67
|
+
- `atp_dumpsys` — query current Activity or Window
|
|
68
|
+
- `atp_logcat_start/read/stop` — manage logcat sessions
|
|
69
|
+
- `mobile_list_elements_on_screen` — dump UI hierarchy
|
|
70
|
+
- `mobile_take_screenshot` — capture screenshot
|
|
71
|
+
|
|
72
|
+
## Logcat Session Lifecycle
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
Test start → atp_logcat_start
|
|
76
|
+
Step 1 → atp_run_step (auto tier fallback)
|
|
77
|
+
Step 2 → atp_run_step (auto tier fallback)
|
|
78
|
+
Step N → atp_run_step (auto tier fallback)
|
|
79
|
+
Test end → atp_logcat_stop
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Result Output
|
|
83
|
+
|
|
84
|
+
Print results as a table:
|
|
85
|
+
|
|
86
|
+
| Step | Expected | Actual | Tier Used | Result |
|
|
87
|
+
|------|----------|--------|-----------|--------|
|
|
88
|
+
| 1 | ... | ... | text | PASS |
|
|
89
|
+
| 2 | ... | ... | uiautomator | PASS |
|
|
90
|
+
| 3 | ... | ... | screenshot | FAIL |
|
|
91
|
+
|
|
92
|
+
At the end, print a summary: total steps, passed, failed.
|
package/README.ko.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# android-test-pilot
|
|
2
|
+
|
|
3
|
+
[English](README.md)
|
|
4
|
+
|
|
5
|
+
Android 앱 테스트 자동화 도구. Claude Code와 연동하여 소스코드 정적 분석부터 실제 디바이스 테스트 실행까지 자동화합니다.
|
|
6
|
+
|
|
7
|
+
## 왜 만들었는가
|
|
8
|
+
|
|
9
|
+
기존 mobile-mcp로 앱을 테스트하면 **스크린샷 촬영 → LLM 이미지 분석 → 다음 동작** 루프를 반복합니다. 이 방식은:
|
|
10
|
+
|
|
11
|
+
- **토큰 비용이 높습니다.** 매 스텝마다 스크린샷 이미지를 LLM에 보내야 합니다.
|
|
12
|
+
- **느립니다.** 스크린샷 캡처 + 이미지 전송 + 분석 대기가 매번 발생합니다.
|
|
13
|
+
|
|
14
|
+
android-test-pilot은 **텍스트 기반 ADB 명령을 1순위 정보 소스**로 사용하여 이 문제를 해결합니다.
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
기존 방식 (mobile-mcp):
|
|
18
|
+
스크린샷 → LLM 이미지 분석 → 다음 동작 → 스크린샷 → ...
|
|
19
|
+
(매 스텝 이미지 토큰 소모, 느림)
|
|
20
|
+
|
|
21
|
+
android-test-pilot:
|
|
22
|
+
dumpsys + logcat 텍스트 → 즉시 판단 → 다음 동작 → ...
|
|
23
|
+
(텍스트 기반, 빠르고 저렴)
|
|
24
|
+
↘ 판단 불가 시에만 uiautomator → 스크린샷 fallback
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Tier 1은 `dumpsys activity`(현재 Activity), `dumpsys window`(포커스 윈도우), logcat(API 응답, View 상태)를 조합하여 앱 상태를 파악합니다. 모두 텍스트이므로 이미지 대비 토큰 소모가 극히 적고, 파싱도 즉시 가능합니다.
|
|
28
|
+
스크린샷은 정말 필요할 때(이미지 렌더링 검증, 예외 팝업)만 Tier 3에서 사용합니다.
|
|
29
|
+
|
|
30
|
+
## 작동 방식
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Step 0 — 정적 분석 (앱 전체 맵 구축)
|
|
34
|
+
Step 1 — 로그 커버리지 확인 & 보강
|
|
35
|
+
↓
|
|
36
|
+
Step 2의 필수 선작업
|
|
37
|
+
|
|
38
|
+
Step 2 — 실제 디바이스 테스트 실행
|
|
39
|
+
Tier 1: 텍스트 기반(dumpsys + logcat) → Tier 2: uiautomator → Tier 3: screenshot
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Step 0: 정적 분석
|
|
43
|
+
|
|
44
|
+
소스코드를 분석하여 앱의 전체 구조를 파악합니다.
|
|
45
|
+
|
|
46
|
+
| 분석 항목 | 산출물 |
|
|
47
|
+
|-----------|--------|
|
|
48
|
+
| 화면 네비게이션 흐름 | `navigation_map.mermaid` |
|
|
49
|
+
| API 연결 & 응답 시나리오 | `api_scenarios.json` |
|
|
50
|
+
| View 상태 매핑 | `view_state_map.json` |
|
|
51
|
+
|
|
52
|
+
### Step 1: 로그 커버리지 확인 & 보강
|
|
53
|
+
|
|
54
|
+
Step 0 결과를 기반으로, 테스트에 필요한 logcat 로그가 소스코드에 있는지 확인하고 부족한 곳에 추가합니다.
|
|
55
|
+
|
|
56
|
+
| 로그 태그 | 용도 | 예시 |
|
|
57
|
+
|-----------|------|------|
|
|
58
|
+
| `ATP_SCREEN` | 화면 진입/전환 | `enter: LoginActivity` |
|
|
59
|
+
| `ATP_RENDER` | View 상태 변경 | `renderState: screen=Login, btnVisible=true` |
|
|
60
|
+
| `ATP_API` | API 응답 | `apiResponse: endpoint=GET /api/users, status=200` |
|
|
61
|
+
|
|
62
|
+
### Step 2: 디바이스 테스트 실행
|
|
63
|
+
|
|
64
|
+
마크다운 시나리오 파일을 읽고 3-Tier 전략으로 테스트합니다.
|
|
65
|
+
|
|
66
|
+
| Tier | 도구 | 사용 조건 | 파악 가능한 정보 |
|
|
67
|
+
|------|------|-----------|----------------|
|
|
68
|
+
| Tier 1 | dumpsys + logcat (텍스트) | 가장 먼저 시도 | 현재 Activity, 포커스 윈도우, View 상태, API 수신 데이터 |
|
|
69
|
+
| Tier 2 | uiautomator + accessibility tree | Tier 1로 판단 불가 시 | 렌더링된 View 구조, resource-id, bounds |
|
|
70
|
+
| Tier 3 | 스크린샷 | 최후 수단 | 이미지 렌더링 검증, 예외 팝업 감지 |
|
|
71
|
+
|
|
72
|
+
## 설치
|
|
73
|
+
|
|
74
|
+
### 요구사항
|
|
75
|
+
|
|
76
|
+
- Node.js >= 18
|
|
77
|
+
- ADB (Android SDK Platform-Tools)
|
|
78
|
+
- Claude Code
|
|
79
|
+
- Android 디바이스 또는 에뮬레이터 (USB 디버깅 활성화)
|
|
80
|
+
|
|
81
|
+
### 설치 방법
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
git clone https://github.com/panicgit/android-test-pilot
|
|
85
|
+
cd android-test-pilot
|
|
86
|
+
npm install
|
|
87
|
+
npm run build
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### MCP 서버 등록
|
|
91
|
+
|
|
92
|
+
테스트 대상 Android 프로젝트 디렉토리에서:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# CLI로 등록 (권장)
|
|
96
|
+
claude mcp add --transport stdio --scope project android-test-pilot \
|
|
97
|
+
-- node /path/to/android-test-pilot/lib/index.js
|
|
98
|
+
|
|
99
|
+
# 또는 .mcp.json 직접 작성
|
|
100
|
+
cat > .mcp.json << 'EOF'
|
|
101
|
+
{
|
|
102
|
+
"mcpServers": {
|
|
103
|
+
"android-test-pilot": {
|
|
104
|
+
"command": "node",
|
|
105
|
+
"args": ["/path/to/android-test-pilot/lib/index.js"],
|
|
106
|
+
"env": {
|
|
107
|
+
"MAX_MCP_OUTPUT_TOKENS": "50000"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
EOF
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 슬래시 커맨드 설치
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
cp -r /path/to/android-test-pilot/.claude/skills/atp \
|
|
119
|
+
/path/to/my-android-app/.claude/skills/atp
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## 사용법
|
|
123
|
+
|
|
124
|
+
Claude Code에서 슬래시 커맨드로 실행합니다.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# 1. 정적 분석 (Step 0)
|
|
128
|
+
/atp:analyze-app
|
|
129
|
+
|
|
130
|
+
# 2. 로그 커버리지 확인 (Step 1)
|
|
131
|
+
/atp:check-logs
|
|
132
|
+
|
|
133
|
+
# 3. 시나리오 작성
|
|
134
|
+
cp /path/to/android-test-pilot/templates/scenario.md scenarios/login.md
|
|
135
|
+
# 시나리오 편집...
|
|
136
|
+
|
|
137
|
+
# 4. 테스트 실행 (Step 2)
|
|
138
|
+
/atp:run-test scenarios/login.md
|
|
139
|
+
|
|
140
|
+
# 산출물 요약 보기
|
|
141
|
+
/atp:app-map
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## 시나리오 파일 작성
|
|
145
|
+
|
|
146
|
+
마크다운으로 자연어 테스트 시나리오를 작성합니다. `templates/scenario.md`를 참고하세요.
|
|
147
|
+
|
|
148
|
+
```markdown
|
|
149
|
+
# 테스트 시나리오: 로그인
|
|
150
|
+
|
|
151
|
+
## 테스트 스텝
|
|
152
|
+
|
|
153
|
+
### Step 1: 앱 실행
|
|
154
|
+
- **동작**: 앱을 실행하고 로그인 화면으로 이동
|
|
155
|
+
- **예상 logcat**:
|
|
156
|
+
- `ATP_SCREEN` → `enter: LoginActivity`
|
|
157
|
+
- **검증**: 로그인 화면이 정상 로드됨
|
|
158
|
+
|
|
159
|
+
### Step 2: 로그인 시도
|
|
160
|
+
- **동작**: 이메일과 비밀번호 입력 후 로그인 버튼 탭
|
|
161
|
+
- **탭 대상**: `resource-id: btn_login`
|
|
162
|
+
- **예상 logcat**:
|
|
163
|
+
- `ATP_API` → `apiResponse: endpoint=POST /api/login, status=200`
|
|
164
|
+
- **검증**: 홈 화면으로 전환됨
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## 프로젝트 구조
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
android-test-pilot/
|
|
171
|
+
├── .claude/skills/atp/ # Claude Code 슬래시 커맨드
|
|
172
|
+
│ ├── analyze-app/SKILL.md # /atp:analyze-app (Step 0)
|
|
173
|
+
│ ├── check-logs/SKILL.md # /atp:check-logs (Step 1)
|
|
174
|
+
│ ├── run-test/SKILL.md # /atp:run-test (Step 2)
|
|
175
|
+
│ └── app-map/SKILL.md # /atp:app-map
|
|
176
|
+
├── src/
|
|
177
|
+
│ ├── index.ts # MCP 서버 진입점
|
|
178
|
+
│ ├── server.ts # MCP 도구 등록
|
|
179
|
+
│ ├── android.ts # AndroidRobot (ADB 래퍼)
|
|
180
|
+
│ ├── robot.ts # Robot 인터페이스
|
|
181
|
+
│ └── tiers/ # Tier 플러그인 시스템
|
|
182
|
+
│ ├── types.ts # TierContext, TierResult 타입
|
|
183
|
+
│ ├── abstract-tier.ts # AbstractTier 추상 클래스
|
|
184
|
+
│ ├── tier-runner.ts # TierRunner 체인 실행기
|
|
185
|
+
│ ├── text-tier.ts # Tier 1: 텍스트 기반 (dumpsys + logcat)
|
|
186
|
+
│ ├── uiautomator-tier.ts # Tier 2: UI 트리
|
|
187
|
+
│ └── screenshot-tier.ts # Tier 3: 스크린샷
|
|
188
|
+
├── templates/
|
|
189
|
+
│ └── scenario.md # 시나리오 템플릿
|
|
190
|
+
└── package.json
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## MCP 도구
|
|
194
|
+
|
|
195
|
+
android-test-pilot은 5개의 MCP 도구를 제공합니다:
|
|
196
|
+
|
|
197
|
+
| 도구 | 설명 |
|
|
198
|
+
|------|------|
|
|
199
|
+
| `atp_run_step` | 단일 테스트 스텝을 3-tier 자동 전환으로 실행 (텍스트 → uiautomator → 스크린샷) |
|
|
200
|
+
| `atp_dumpsys` | 현재 Activity 또는 포커스 윈도우 조회 (텍스트 기반) |
|
|
201
|
+
| `atp_logcat_start` | ATP 태그 필터링으로 logcat 스트리밍 세션 시작 |
|
|
202
|
+
| `atp_logcat_read` | 활성 세션에서 수집된 로그 라인 읽기 (증분 읽기 지원) |
|
|
203
|
+
| `atp_logcat_stop` | logcat 세션 중단 및 통계 반환 |
|
|
204
|
+
|
|
205
|
+
기존 [mobile-mcp](https://github.com/mobile-next/mobile-mcp) 도구(`mobile_take_screenshot`, `mobile_list_elements_on_screen`, `mobile_click_on_screen_at_coordinates` 등)도 모두 사용 가능합니다.
|
|
206
|
+
|
|
207
|
+
## Tier 플러그인 확장
|
|
208
|
+
|
|
209
|
+
커스텀 Tier를 추가하여 테스트 전략을 확장할 수 있습니다.
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { AbstractTier } from "./tiers/abstract-tier";
|
|
213
|
+
import { TierContext, TierResult } from "./tiers/types";
|
|
214
|
+
|
|
215
|
+
class MyCustomTier extends AbstractTier {
|
|
216
|
+
readonly name = "custom-monitor";
|
|
217
|
+
readonly priority = 1.5; // Tier 1과 2 사이에 삽입
|
|
218
|
+
|
|
219
|
+
async canHandle(context: TierContext): Promise<boolean> {
|
|
220
|
+
// 이 Tier를 사용할 수 있는지 확인
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async execute(context: TierContext): Promise<TierResult> {
|
|
224
|
+
// 테스트 실행 로직
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## 기술 기반
|
|
230
|
+
|
|
231
|
+
[mobile-mcp](https://github.com/mobile-next/mobile-mcp) (Apache-2.0)를 포크하여 Android 테스트 자동화에 특화했습니다.
|
|
232
|
+
|
|
233
|
+
| 구성 요소 | 역할 |
|
|
234
|
+
|-----------|------|
|
|
235
|
+
| Claude Code 슬래시 커맨드 | 사용자 인터페이스, 워크플로우 오케스트레이터 |
|
|
236
|
+
| Claude Code 네이티브 기능 | 소스 파일 읽기, bash 실행, 파일 쓰기 |
|
|
237
|
+
| mobile-mcp (포크) | 스크린샷, accessibility tree, logcat streaming |
|
|
238
|
+
|
|
239
|
+
## 라이선스
|
|
240
|
+
|
|
241
|
+
Apache-2.0
|