This commit is contained in:
2026-04-21 12:57:33 +08:00
commit c000eb12f8
64 changed files with 7970 additions and 0 deletions

View File

@@ -0,0 +1,232 @@
# Testing Patterns
**Analysis Date:** 2026-04-16
## Framework
**Runner:**
- `flutter_test` (Flutter SDK built-in)
- `integration_test` (Flutter SDK built-in, for E2E/integration tests)
- No explicit `test` package dependency (uses Flutter's bundled test framework)
**Assertion Library:**
- Built-in `flutter_test` matchers (`expect`, `findsOneWidget`, `isEmpty`, `isInstanceOf`)
**Dependencies:**
- `flutter_test` (sdk: flutter) - Unit and widget testing
- `flutter_lints` (^3.0.0) - Code analysis
- `plugin_platform_interface` (^2.0.2) - Required for mock platform interface mixin
**Run Commands:**
```bash
flutter test # Run all unit tests
flutter test --coverage # Run tests with coverage
flutter test test/ch34_test.dart # Run a specific test file
flutter test integration_test/ # Run integration tests (from example/)
```
## Test Structure
**Test File Organization:**
- Plugin tests in `D:/code/new_git_code/flutter/ch34/test/`:
- `ch34_test.dart` - Unit tests with mock platform
- `ch34_method_channel_test.dart` - MethodChannel-level tests with mock handler
- Example app tests in `D:/code/new_git_code/flutter/ch34/example/test/`:
- `widget_test.dart` - Widget tests for example app
- Integration tests in `D:/code/new_git_code/flutter/ch34/example/integration_test/`:
- `plugin_integration_test.dart` - End-to-end plugin tests on real device
**Naming:**
- Test files: `{source_file}_test.dart` pattern
- Integration test files: `{feature}_integration_test.dart`
**Test Entry Pattern:**
All tests call framework initialization before running:
```dart
// Unit tests
TestWidgetsFlutterBinding.ensureInitialized();
// Integration tests
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
```
**Suite Organization:**
Unit tests follow a consistent pattern:
```dart
// D:/code/new_git_code/flutter/ch34/test/ch34_test.dart
void main() {
MethodChannelCh34.registerDefault();
final Ch34Platform initialPlatform = Ch34Platform.instance;
test('$MethodChannelCh34 is the default instance', () {
expect(initialPlatform, isInstanceOf<MethodChannelCh34>());
});
test('getPlatformVersion', () async {
MockCh34Platform fakePlatform = MockCh34Platform();
Ch34Platform.instance = fakePlatform;
expect(await Ch34Manager.getPlatformVersion(), '42');
});
test('enumDevice returns empty list', () async {
MockCh34Platform fakePlatform = MockCh34Platform();
Ch34Platform.instance = fakePlatform;
final devices = await Ch34Manager.enumDevice();
expect(devices, isEmpty);
});
}
```
## Mocking
**Framework:** Manual mock classes (no mockito or mocktail dependency)
**Platform Mock Pattern:**
`D:/code/new_git_code/flutter/ch34/test/ch34_test.dart` uses `MockPlatformInterfaceMixin` for creating test doubles:
```dart
class MockCh34Platform
with MockPlatformInterfaceMixin
implements Ch34Platform {
@override
Future<String?> getPlatformVersion() => Future.value('42');
@override
Future<List<UsbDeviceInfo>> enumDevice() => Future.value([]);
// ... all 30+ methods must be overridden
}
```
**Mock Usage Pattern:**
Mock instances are swapped into the platform interface before each test:
```dart
MockCh34Platform fakePlatform = MockCh34Platform();
Ch34Platform.instance = fakePlatform;
expect(await Ch34Manager.getPlatformVersion(), '42');
```
**MethodChannel Mock Pattern:**
`D:/code/new_git_code/flutter/ch34/test/ch34_method_channel_test.dart` uses `setMockMethodCallHandler` for low-level channel mocking:
```dart
const MethodChannel channel = MethodChannel('ch34');
setUp(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(
channel,
(MethodCall methodCall) async {
return '42'; // Returns same value for all method calls
},
);
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, null);
});
```
**What to Mock:**
- Platform interface layer (`Ch34Platform`) for testing `Ch34Manager` delegation
- `MethodChannel` for testing `MethodChannelCh34` channel mapping
**What NOT to Mock:**
- Native Android code (tested via integration tests on real device)
- EventChannel streams (not currently mocked in any test)
## Coverage
**Requirements:** No coverage target enforced
**Current State:**
- Only 2 unit test assertions beyond boilerplate (`getPlatformVersion`, `enumDevice returns empty list`)
- MethodChannel test has only 1 assertion (`getPlatformVersion`)
- Integration test has 1 assertion (`getPlatformVersion` on real device)
- Most platform methods have zero test coverage (GPIO, serial I/O, modem status, signal control, etc.)
**View Coverage:**
```bash
flutter test --coverage
# Coverage written to coverage/lcov.info
```
## Test Locations
**Unit Tests:**
- `D:/code/new_git_code/flutter/ch34/test/ch34_test.dart` - Ch34Manager + mock platform
- `D:/code/new_git_code/flutter/ch34/test/ch34_method_channel_test.dart` - MethodChannel tests
**Integration Tests:**
- `D:/code/new_git_code/flutter/ch34/example/integration_test/plugin_integration_test.dart` - Real device tests
**Widget Tests:**
- `D:/code/new_git_code/flutter/ch34/example/test/widget_test.dart` - Example app widget test (currently outdated - looks for "Running on:" text that no longer exists)
## Test Types
**Unit Tests:**
- Scope: Test `Ch34Manager` delegation to mocked platform
- Approach: Replace `Ch34Platform.instance` with `MockCh34Platform`
- Current coverage: 2 methods tested out of 30+ API methods
**Integration Tests:**
- Framework: `integration_test` package
- Approach: Run on real Android device with actual USB hardware
- Current coverage: 1 test (`getPlatformVersion`)
**E2E Tests:**
- No dedicated E2E test framework beyond `integration_test`
## Common Patterns
**Async Testing:**
All platform method tests use `async/await`:
```dart
test('enumDevice returns empty list', () async {
MockCh34Platform fakePlatform = MockCh34Platform();
Ch34Platform.instance = fakePlatform;
final devices = await Ch34Manager.enumDevice();
expect(devices, isEmpty);
});
```
**Error Testing:**
Mock throws exceptions to test error paths:
```dart
@override
Future<GpioStatus> queryGpioStatus(String deviceName, int gpioIndex) =>
throw const Ch34Exception('Not supported');
```
**Setup/Teardown Pattern:**
```dart
setUp(() {
// Configure mock method channel handler
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, handler);
});
tearDown(() {
// Clean up mock handler
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, null);
});
```
## CI Testing
**CI Pipeline:** Not detected - no `.github/workflows/`, `.gitlab-ci.yml`, or `azure-pipelines.yml` found.
**Recommendation:** Tests should be run via `flutter analyze && flutter test` in any CI pipeline.
---
*Testing analysis: 2026-04-16*