Skip to content

Commit 901edc1

Browse files
committed
docs: add test infrastructure documentation for MockCommandExecutor and common test utilities
1 parent 8da1cfc commit 901edc1

File tree

5 files changed

+166
-62
lines changed

5 files changed

+166
-62
lines changed

.github/ISSUE_TEMPLATE/feature_request.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ labels: "enhancement"
66
assignees: ""
77
---
88

9-
## Is your feature request related to a problem? Please describe.
9+
## Is your feature request related to a problem? Please describe
1010

1111
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
1212

CLAUDE.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ cargo test --bins --tests
169169
# Run all tests including doctests (may have import issues in examples)
170170
cargo test
171171

172+
# Run all tests with test-utils feature (required for integration tests)
173+
cargo test --features test-utils
174+
172175
# Run main test suites
173176
cargo test --test comprehensive_integration_test
174177
cargo test --test device_creation_navigation_test
@@ -186,10 +189,46 @@ cargo test --test background_task_test
186189
# Performance validation
187190
cargo test responsiveness_validation_test -- --nocapture
188191

189-
# Test coverage measurement
192+
# Test coverage measurement with cargo-llvm-cov (recommended)
193+
cargo llvm-cov --lcov --output-path coverage/lcov.info --features test-utils \
194+
--ignore-filename-regex '(tests/|src/main\.rs|src/bin/|src/app/test_helpers\.rs|src/fixtures/|src/managers/mock\.rs)'
195+
196+
# Alternative: Test coverage with tarpaulin
190197
cargo tarpaulin --features test-utils --ignore-tests --exclude-files "*/tests/*" --exclude-files "*/examples/*"
191198
```
192199

200+
### Test Infrastructure
201+
202+
#### MockCommandExecutor
203+
204+
All tests now use `MockCommandExecutor` to simulate Android SDK commands without requiring actual SDK installation:
205+
206+
```rust
207+
// Example from tests
208+
let mock_executor = MockCommandExecutor::new()
209+
.with_success("avdmanager", &["list", "avd"], "")
210+
.with_success("adb", &["devices"], "List of devices attached\n");
211+
212+
let manager = AndroidManager::with_executor(Arc::new(mock_executor));
213+
```
214+
215+
#### Common Test Module
216+
217+
The `tests/common/mod.rs` module provides shared test utilities:
218+
219+
- `setup_mock_android_sdk()` - Creates a temporary mock Android SDK directory structure
220+
- Sets up executable scripts for `avdmanager`, `adb`, `sdkmanager`, and `emulator`
221+
- Ensures tests can run in CI environments without Android SDK
222+
223+
#### Environment Setup
224+
225+
Tests requiring Android SDK mock should set the `ANDROID_HOME` environment variable:
226+
227+
```rust
228+
let temp_dir = setup_mock_android_sdk();
229+
std::env::set_var("ANDROID_HOME", temp_dir.path());
230+
```
231+
193232
### Test Coverage
194233

195234
- **Current Coverage**: 28.33% (1,594/5,627 lines covered)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
A TUI for managing Android emulators and iOS simulators.
77

8-
https://github.com/user-attachments/assets/3f4bfde6-6e54-45bd-9a7c-0cb2eeb2f861
8+
<https://github.com/user-attachments/assets/3f4bfde6-6e54-45bd-9a7c-0cb2eeb2f861>
99

1010
## Features
1111

docs/DEVELOPMENT.md

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ cargo watch -x test
198198
# Run specific test
199199
cargo test test_name -- --nocapture
200200

201+
# Run tests with test-utils feature (required for integration tests)
202+
cargo test --features test-utils
203+
204+
# Run tests with CI environment setup
205+
RUST_TEST_THREADS=1 cargo test --features test-utils
206+
201207
# Check code without building
202208
cargo check
203209

@@ -338,19 +344,31 @@ Located in `tests/` directory:
338344

339345
```rust
340346
// tests/device_lifecycle_test.rs
341-
use emu::managers::AndroidManager;
342-
use emu::models::DeviceConfig;
347+
use emu::managers::android::AndroidManager;
348+
use emu::managers::common::DeviceConfig;
349+
use emu::utils::command_executor::mock::MockCommandExecutor;
350+
use std::sync::Arc;
351+
352+
mod common;
353+
use common::setup_mock_android_sdk;
343354

344355
#[tokio::test]
345356
async fn test_complete_device_lifecycle() {
346-
let manager = AndroidManager::new().unwrap();
357+
// Setup mock Android SDK
358+
let temp_dir = setup_mock_android_sdk();
359+
std::env::set_var("ANDROID_HOME", temp_dir.path());
360+
361+
// Create mock executor
362+
let mock_executor = MockCommandExecutor::new()
363+
.with_success("avdmanager", &["list", "avd"], "")
364+
.with_success("adb", &["devices"], "List of devices attached\n");
365+
366+
// Create manager with mock
367+
let manager = AndroidManager::with_executor(Arc::new(mock_executor)).unwrap();
347368

348369
// Test complete workflow
349370
let config = DeviceConfig::new("test_device", "pixel_7", "31");
350-
manager.create_device(&config).await.unwrap();
351-
manager.start_device("test_device").await.unwrap();
352-
manager.stop_device("test_device").await.unwrap();
353-
manager.delete_device("test_device").await.unwrap();
371+
// Note: In real tests, we would test against mock responses
354372
}
355373
```
356374

@@ -377,6 +395,9 @@ cargo test --bins --tests
377395
# Run all tests including doctests (may have import issues in examples)
378396
cargo test
379397

398+
# Run all tests with test-utils feature (required for integration tests)
399+
cargo test --features test-utils
400+
380401
# Run with output
381402
cargo test -- --nocapture
382403

@@ -392,8 +413,12 @@ cargo test android::
392413
# Run performance tests
393414
cargo test responsiveness_validation_test -- --nocapture
394415

395-
# Run tests with coverage (requires cargo-tarpaulin)
396-
cargo tarpaulin --out Html
416+
# Test coverage with cargo-llvm-cov (recommended)
417+
cargo llvm-cov --lcov --output-path coverage/lcov.info --features test-utils \
418+
--ignore-filename-regex '(tests/|src/main\.rs|src/bin/|src/app/test_helpers\.rs|src/fixtures/|src/managers/mock\.rs)'
419+
420+
# Alternative: Test coverage with tarpaulin
421+
cargo tarpaulin --features test-utils --out Html
397422
```
398423

399424
### Test Guidelines
@@ -409,30 +434,43 @@ cargo tarpaulin --out Html
409434

410435
#### Mock Usage
411436

412-
```rust
413-
use mockall::predicate::*;
414-
use mockall::mock;
437+
The project uses `MockCommandExecutor` for testing Android SDK commands:
415438

416-
mock! {
417-
AndroidManager {}
439+
```rust
440+
use emu::utils::command_executor::mock::MockCommandExecutor;
441+
use std::sync::Arc;
418442

419-
#[async_trait]
420-
impl DeviceManager for AndroidManager {
421-
async fn list_devices(&self) -> Result<Vec<AndroidDevice>>;
422-
async fn start_device(&self, id: &str) -> Result<()>;
423-
}
443+
#[tokio::test]
444+
async fn test_with_mock_executor() {
445+
// Create mock executor with predefined responses
446+
let mock_executor = MockCommandExecutor::new()
447+
.with_success("avdmanager", &["list", "avd"],
448+
"Available Android Virtual Devices:\n Name: test_device\n Path: /path/to/avd")
449+
.with_success("adb", &["devices"],
450+
"List of devices attached\nemulator-5554\tdevice\n");
451+
452+
// Use with AndroidManager
453+
let manager = AndroidManager::with_executor(Arc::new(mock_executor)).unwrap();
454+
455+
// Test operations
456+
let devices = manager.list_devices().await.unwrap();
457+
assert_eq!(devices.len(), 1);
424458
}
459+
```
425460

426-
#[tokio::test]
427-
async fn test_with_mock() {
428-
let mut mock_manager = MockAndroidManager::new();
461+
For common test setup, use the shared utilities:
429462

430-
mock_manager
431-
.expect_list_devices()
432-
.returning(|| Ok(vec![create_mock_device()]));
463+
```rust
464+
mod common;
465+
use common::setup_mock_android_sdk;
433466

434-
let devices = mock_manager.list_devices().await.unwrap();
435-
assert_eq!(devices.len(), 1);
467+
#[tokio::test]
468+
async fn test_with_mock_sdk() {
469+
// Setup mock Android SDK directory
470+
let temp_dir = setup_mock_android_sdk();
471+
std::env::set_var("ANDROID_HOME", temp_dir.path());
472+
473+
// Continue with test...
436474
}
437475
```
438476

@@ -1013,6 +1051,7 @@ impl DeviceConfig {
10131051
- Manual updates are only needed for major releases or special announcements
10141052

10151053
4. Commit the version bump:
1054+
10161055
```bash
10171056
git add Cargo.toml CHANGELOG.md
10181057
git commit -m "chore: bump version to v0.2.2"

docs/PERFORMANCE_IMPROVEMENTS.md

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,63 +39,82 @@ Emu プロジェクトにおけるテスト品質向上とテストパフォー
3939
- **テスト安定性**: 一貫した出力による信頼性向上
4040
- **デバッグ効率**: 予測可能なテストデータ
4141

42-
### フェーズ 2: Managers 層テスト強化 🔄
42+
### フェーズ 2: Managers 層テスト強化
4343

4444
#### AndroidManager テスト拡張
4545

46-
- **AVD 管理機能**: `create_device()`, `delete_device()`, `list_devices()`
47-
- **状態管理**: デバイス起動・停止・ステータス監視
48-
- **パーサーテスト**: 実際のコマンド出力のパース検証
49-
- **エラーハンドリング**: 各種エラーシナリオの対応
46+
- **AVD 管理機能**: `create_device()`, `delete_device()`, `list_devices()`
47+
- **状態管理**: デバイス起動・停止・ステータス監視 ✅
48+
- **パーサーテスト**: 実際のコマンド出力のパース検証 ✅
49+
- **エラーハンドリング**: 各種エラーシナリオの対応 ✅
50+
- **MockCommandExecutor 使用**: 全テストでモック化を実現 ✅
5051

5152
#### iOSManager テスト拡張
5253

53-
- **Simulator 管理**: xcrun simctl コマンドの完全テスト
54-
- **JSON パーサー**: 構造化された出力データの解析
55-
- **状態遷移**: Boot/Shutdown プロセスの検証
56-
- **プラットフォーム判定**: macOS 環境での動作保証
54+
- **Simulator 管理**: xcrun simctl コマンドの完全テスト ✅
55+
- **JSON パーサー**: 構造化された出力データの解析 ✅
56+
- **状態遷移**: Boot/Shutdown プロセスの検証 ✅
57+
- **プラットフォーム判定**: macOS 環境での動作保証 ✅
58+
- **非 macOS 対応**: スタブ実装の適切なテスト ✅
5759

5860
#### 実装手法
5961

6062
```rust
61-
// フィクスチャーベースのテスト例
63+
// MockCommandExecutor によるテスト例
6264
fn test_android_device_creation() {
63-
let mock = MockDeviceManager::new()
64-
.with_fixture_outputs("android_device_creation");
65+
let mock_executor = MockCommandExecutor::new()
66+
.with_success("avdmanager", &["create", "avd"], "AVD created successfully")
67+
.with_success("adb", &["devices"], "List of devices attached\n");
6568

66-
let result = mock.create_device(&device_config).await;
69+
let manager = AndroidManager::with_executor(Arc::new(mock_executor)).unwrap();
70+
let result = manager.create_device(&device_config).await;
6771
assert!(result.is_ok());
6872
}
6973
```
7074

71-
### フェーズ 3: 統合テスト実装 🔄
75+
### フェーズ 3: 統合テスト実装
7276

7377
#### Utils/Command.rs テスト強化
7478

75-
- **外部コマンド実行**: フィクスチャーによるモック化
76-
- **リトライ機能**: 失敗・成功パターンの検証
77-
- **タイムアウト処理**: 長時間実行コマンドの対応
78-
- **エラー無視実行**: `run_ignoring_errors()` の完全テスト
79+
- **外部コマンド実行**: MockCommandExecutor によるモック化 ✅
80+
- **リトライ機能**: 失敗・成功パターンの検証
81+
- **タイムアウト処理**: 長時間実行コマンドの対応
82+
- **エラー無視実行**: `run_ignoring_errors()` の完全テスト
7983

8084
#### Models 層完全テスト
8185

82-
- **Error.rs**: 全エラータイプとユーザーフレンドリメッセージ
83-
- **Platform.rs**: プラットフォーム判定ロジックの完全検証
84-
- **Device.rs**: デバイス情報の検証とバリデーション
86+
- **Error.rs**: 全エラータイプとユーザーフレンドリメッセージ
87+
- **Platform.rs**: プラットフォーム判定ロジックの完全検証
88+
- **Device.rs**: デバイス情報の検証とバリデーション
8589

8690
#### App 層統合テスト
8791

88-
- **Events.rs**: キーボード入力のイベント変換
89-
- **EventProcessing.rs**: 非同期イベント処理とデバウンス
90-
- **State.rs**: アプリケーション状態管理の統合テスト
92+
- **Events.rs**: キーボード入力のイベント変換
93+
- **EventProcessing.rs**: 非同期イベント処理とデバウンス
94+
- **State.rs**: アプリケーション状態管理の統合テスト
9195

92-
### フェーズ 4: CI/CD 最適化 🔄
96+
#### 共通テストインフラストラクチャ
97+
98+
- **tests/common/mod.rs**: テストユーティリティの集約 ✅
99+
- **setup_mock_android_sdk()**: モック SDK ディレクトリ作成 ✅
100+
- **コード重複削減**: ~450 行のテストコード削減 ✅
101+
102+
### フェーズ 4: CI/CD 最適化 ✅
93103

94104
#### テスト実行環境
95105

96-
- **並列実行**: MockDeviceManager による高速テスト
97-
- **環境依存排除**: エミュレータ・ SDK 不要の実行
98-
- **キャッシュ活用**: フィクスチャーデータの効率的管理
106+
- **並列実行**: MockDeviceManager による高速テスト ✅
107+
- **環境依存排除**: エミュレータ・ SDK 不要の実行 ✅
108+
- **キャッシュ活用**: フィクスチャーデータの効率的管理 ✅
109+
- **MockCommandExecutor**: Android SDK コマンドの完全モック化 ✅
110+
- **共通テストモジュール**: `tests/common/mod.rs` による重複削減 ✅
111+
112+
#### CI 環境の改善
113+
114+
- **Android SDK 不要化**: `setup_mock_android_sdk()` によるモック SDK 作成 ✅
115+
- **環境変数設定**: `ANDROID_HOME` の自動設定 ✅
116+
- **Coverage 生成修正**: `mkdir -p coverage` によるディレクトリ作成 ✅
117+
- **iOS テスト修正**: 非 macOS 環境での適切な処理 ✅
99118

100119
#### 品質保証プロセス
101120

@@ -233,10 +252,17 @@ tests/fixtures/
233252

234253
### 実装時の考慮点
235254

236-
- **段階的実装**: 一度にすべてを変更せず、フェーズごとに確実に実装
237-
- **既存テスト保持**: 現在のテストを維持しながら新テストを追加
238-
- **データ品質**: フィクスチャーデータの定期的な検証と更新
239-
- **ドキュメント維持**: テスト手法の文書化とチーム共有
255+
- **段階的実装**: 一度にすべてを変更せず、フェーズごとに確実に実装 ✅
256+
- **既存テスト保持**: 現在のテストを維持しながら新テストを追加 ✅
257+
- **データ品質**: フィクスチャーデータの定期的な検証と更新 ✅
258+
- **ドキュメント維持**: テスト手法の文書化とチーム共有 ✅
259+
260+
### テストインフラストラクチャの改善点
261+
262+
- **MockCommandExecutor**: Android SDK コマンドの完全モック化を実現
263+
- **共通テストモジュール**: `tests/common/mod.rs` による重複コードの削減
264+
- **環境変数自動設定**: `ANDROID_HOME` の自動設定でテスト実行を簡素化
265+
- **CI 互換性**: GitHub Actions での安定したテスト実行を実現
240266

241267
### パフォーマンス最適化
242268

0 commit comments

Comments
 (0)