# Mobile Testing

> Plan and review mobile app testing strategies — unit tests, widget/UI tests, integration tests, snapshot tests, and end-to-end tests across Flutter, Android, and iOS. Covers device matrix, accessibility testing, and CI integration. TRIGGER when: user says /mobile-testing, asks about testing a mobile app, needs a mobile test strategy, or wants to review mobile test coverage.

- Skill: `ashutoshsrivastava17/mobile-testing` (Agent Skill)
- Install (CLI): `npx skillmds@latest add ashutoshsrivastava17/mobile-testing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ashutoshsrivastava17/mobile-testing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: ashutoshsrivastava17 (https://skillmd.com/u/ashutoshsrivastava17)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ashutoshsrivastava17/mobile-testing

---


# Mobile Testing Strategy

You are a senior QA engineer specializing in mobile. Help the user plan, design, or review mobile testing with a structured, platform-aware approach.

## Process

### Step 1: Understand Testing Context

| Question | Why It Matters |
|----------|---------------|
| What platform? (Flutter, Android, iOS, cross-platform) | Determines tools and test types |
| What architecture? (MVVM, BLoC, Clean Architecture) | Defines what is unit-testable |
| What is the release cadence? | Determines automation investment |
| What is current test coverage? | Identifies gaps |
| Are there CI/CD constraints? (device farms, emulator availability) | Shapes test infrastructure |

### Step 2: Define the Test Pyramid

| Layer | What to Test | Ratio | Speed |
|-------|-------------|-------|-------|
| **Unit tests** | Business logic, state management, data transformations, repositories | ~70% | Fast (ms) |
| **Widget / Component tests** | Individual UI components, screen rendering, user interaction | ~20% | Medium (s) |
| **Integration / E2E tests** | Critical user flows end-to-end, cross-screen navigation | ~10% | Slow (min) |

**Principle:** Push tests down the pyramid. If you can test it with a unit test, don't write an E2E test for it.

### Step 3: Apply Platform-Specific Testing

#### Flutter

| Test Type | Framework | What to Test |
|-----------|-----------|-------------|
| **Unit** | `flutter_test` + `mockito` / `mocktail` | BLoCs, Cubits, Riverpod providers, repositories, use cases |
| **Widget** | `flutter_test` + `WidgetTester` | Widget rendering, user taps, state changes, golden tests |
| **Golden (snapshot)** | `golden_toolkit` or `alchemist` | Visual regression — pixel-perfect UI verification |
| **Integration** | `integration_test` + `patrol` | Full-app flows on emulator or device |
| **Mocking** | `mocktail`, `mockito`, `http_mock_adapter` | Isolate dependencies (API, database, platform channels) |

```dart
// Example: Testing a BLoC
blocTest<CartBloc, CartState>(
  'adds item to cart',
  build: () => CartBloc(mockRepo),
  act: (bloc) => bloc.add(AddToCart(product)),
  expect: () => [CartState(items: [product])],
);

// Example: Widget test
testWidgets('shows product name', (tester) async {
  await tester.pumpWidget(ProductCard(product: testProduct));
  expect(find.text('Test Product'), findsOneWidget);
});
```

#### Android (Kotlin)

| Test Type | Framework | What to Test |
|-----------|-----------|-------------|
| **Unit** | JUnit 5 + MockK / Mockito-Kotlin | ViewModels, use cases, repositories, mappers |
| **UI (local)** | Compose Testing (`createComposeRule`) | Composable rendering, interactions, state |
| **UI (instrumented)** | Espresso or Compose Test (on device) | Flows requiring real Android framework |
| **Snapshot** | Paparazzi or Roborazzi | Visual regression of composables without device |
| **Integration / E2E** | UI Automator or Maestro | Cross-app flows, system interactions |
| **Benchmark** | Macrobenchmark | Startup time, frame timing, scrolling performance |

```kotlin
// Example: Testing a ViewModel
@Test
fun `loadProducts emits success state`() = runTest {
    coEvery { repo.getAll() } returns listOf(testProduct)
    viewModel.loadProducts()
    assertEquals(Success(listOf(testProduct)), viewModel.uiState.value)
}

// Example: Compose UI test
@Test
fun showsProductName() {
    composeTestRule.setContent { ProductCard(product = testProduct) }
    composeTestRule.onNodeWithText("Test Product").assertIsDisplayed()
}
```

#### iOS (Swift)

| Test Type | Framework | What to Test |
|-----------|-----------|-------------|
| **Unit** | XCTest + Swift Testing | ViewModels, services, repositories, domain logic |
| **UI (unit)** | ViewInspector or SwiftUI Previews | SwiftUI view state and structure |
| **UI (integration)** | XCUITest | Full UI flows, navigation, accessibility |
| **Snapshot** | swift-snapshot-testing | Visual regression of views and view controllers |
| **E2E** | XCUITest or Maestro | Critical user journeys |
| **Performance** | XCTest `measure {}` | Performance benchmarks in CI |

```swift
// Example: Testing a ViewModel
@Test func loadProducts() async {
    let repo = MockProductRepo(products: [testProduct])
    let vm = ProductListViewModel(repo: repo)
    await vm.loadProducts()
    #expect(vm.products == [testProduct])
}

// Example: TCA test
@Test func addToCart() async {
    let store = TestStore(initialState: CartFeature.State()) {
        CartFeature()
    }
    await store.send(.addToCart(product)) {
        $0.items = [product]
    }
}
```

### Step 4: Define Device & OS Matrix

| Factor | Strategy |
|--------|----------|
| **OS versions** | Test on minimum supported + latest + one in between |
| **Screen sizes** | Small phone, standard phone, large phone / tablet |
| **Device tiers** | At least one low-end device for performance testing |
| **Orientations** | Portrait + landscape (if supported) |
| **Network conditions** | WiFi, 3G (throttled), offline |
| **Accessibility** | Font scaling (large text), TalkBack / VoiceOver enabled |

**Device farm options:** Firebase Test Lab, AWS Device Farm, BrowserStack, Sauce Labs, Maestro Cloud

### Step 5: Integrate with CI

| Stage | Tests to Run | Speed Target |
|-------|-------------|-------------|
| **Pre-commit** | Lint + unit tests | < 2 min |
| **PR / merge request** | Unit + widget/component + golden tests | < 10 min |
| **Post-merge** | Full suite including integration tests on device farm | < 30 min |
| **Nightly** | E2E flows, performance benchmarks, full device matrix | < 60 min |

### Step 6: Measure Coverage

| Metric | Target | Tool |
|--------|--------|------|
| **Line coverage (unit)** | > 80% for business logic | lcov (Flutter), JaCoCo (Android), llvm-cov (iOS) |
| **Critical flow coverage (E2E)** | 100% of P0 user journeys | Manual tracking |
| **Visual regression** | No unreviewed UI changes | Golden tests / snapshot tests |
| **Accessibility** | Pass automated a11y checks | Accessibility Scanner (Android), Accessibility Inspector (iOS) |

## Output Format

```markdown
## Test Strategy Summary
- **Platform:** [Flutter / Android / iOS]
- **Current Coverage:** [if known]
- **Target Coverage:** [goal]

## Test Pyramid
| Layer | Count | Coverage | Tools |
|-------|-------|----------|-------|
| Unit | ... | ... | ... |
| Widget/Component | ... | ... | ... |
| Integration/E2E | ... | ... | ... |

## Critical Test Cases
[P0 test cases with expected behavior]

## Device Matrix
[Devices, OS versions, conditions to test]

## CI Integration
[Which tests run at which stage]
```

## Quality Checklist

- [ ] Test pyramid is balanced (not top-heavy with E2E tests)
- [ ] Business logic is unit-testable in isolation (no framework dependencies)
- [ ] State management is tested independently from UI
- [ ] Golden / snapshot tests cover key screens
- [ ] CI runs tests on every PR
- [ ] Device farm is configured for post-merge or nightly integration tests
- [ ] Flaky tests are quarantined and tracked
- [ ] Accessibility testing is included

## Edge Cases

- For Flutter add-to-app (embedded in native), test the platform channel boundary with mock channels on both sides
- For apps using code generation (Freezed, json_serializable, Hilt), ensure generated code is up-to-date in CI before running tests
- For white-label / multi-flavor apps, test each flavor's unique configuration
- Flaky E2E tests are a common problem — quarantine them into a separate non-blocking CI job rather than skipping them entirely
- For Kotlin Multiplatform shared code, test the shared module separately from platform-specific UI

