docs: map existing codebase

This commit is contained in:
2026-03-30 15:21:07 +08:00
commit 3c2bb02e33
7 changed files with 1320 additions and 0 deletions

View File

@@ -0,0 +1,284 @@
# Testing Patterns
**Analysis Date:** 2026-03-30
## Test Framework
**Runner:**
- Flutter Test Framework (flutter_test SDK)
- Dart SDK: ^3.9.0
- Config: `analysis_options.yaml` (linting only, no test config file)
**Assertion Library:**
- flutter_test package: `expect()`, `findsOneWidget`, `isInstanceOf<T>()`
**Run Commands:**
```bash
flutter test # Run all tests
flutter test test/arc_test.dart # Run specific test file
flutter test --coverage # Run with coverage
```
## Test File Organization
**Location:**
- Plugin tests: `test/` directory (co-located with lib)
- Example tests: `example/test/` directory
- Java tests: `android/src/test/java/`
**Naming:**
- Dart: `*_test.dart` pattern (`arc_test.dart`, `arc_method_channel_test.dart`, `widget_test.dart`)
- Java: `*Test.java` pattern (`ArcPluginTest.java`)
**Structure:**
```
arc/
├── test/
│ ├── arc_test.dart # Platform interface tests
│ └── arc_method_channel_test.dart # Method channel tests
├── example/
│ └── test/
│ └── widget_test.dart # Widget tests
└── android/
└── src/
└── test/
└── java/
└── com/xiarui/arc/
└── ArcPluginTest.java
```
## Test Structure
**Dart Unit Tests:**
```dart
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final ArcPlatform initialPlatform = ArcPlatform.instance;
test('$MethodChannelArc is the default instance', () {
expect(initialPlatform, isInstanceOf<MethodChannelArc>());
});
test('getPlatformVersion', () async {
Arc arcPlugin = Arc();
MockArcPlatform fakePlatform = MockArcPlatform();
ArcPlatform.instance = fakePlatform;
expect(await arcPlugin.getPlatformVersion(), '42');
});
}
```
**Java Unit Tests:**
```java
public class ArcPluginTest {
@Test
public void onMethodCall_getPlatformVersion_returnsExpectedValue() {
ArcPlugin plugin = new ArcPlugin();
final MethodCall call = new MethodCall("getPlatformVersion", null);
MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
plugin.onMethodCall(call, mockResult);
verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE);
}
}
```
## Mocking
**Dart Mocking:**
- `MockPlatformInterfaceMixin` from plugin_platform_interface
- Custom mock class implementing platform interface
**Example:**
```dart
class MockArcPlatform
with MockPlatformInterfaceMixin
implements ArcPlatform {
@override
Future<String?> getPlatformVersion() => Future.value('42');
@override
Future<Map<String, dynamic>?> activeOnline({
required String appId,
required String sdkKey,
required String activeKey,
}) => Future.value({'success': true, 'errorCode': 0, 'message': 'success'});
}
```
**Method Channel Mocking:**
```dart
setUp(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
channel,
(MethodCall methodCall) async {
return '42';
},
);
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(channel, null);
});
```
**Java Mocking:**
- Mockito framework
- `mock(Class.class)` for mock objects
- `verify(mock).method(args)` for verification
**What to Mock:**
- Platform interfaces for unit testing
- Method channels for integration testing
- Native engine calls
**What NOT to Mock:**
- Data transformation logic (test directly)
- Simple utility functions
## Fixtures and Factories
**Test Data:**
- Mock return values defined inline
- Simple string/int values: `'42'`, `0`, `true`
**Example Mock Data:**
```dart
@override
Future<Map<String, dynamic>?> detectFaces({
required Uint8List data,
required int width,
required int height,
int format = 2050,
}) => Future.value({
'success': true,
'errorCode': 0,
'faceList': [],
'rgbLiveness': 1,
'isRgbAlive': true
});
```
**Location:**
- Mock implementations in test files
- No separate fixture files
## Coverage
**Requirements:** None enforced
**View Coverage:**
```bash
flutter test --coverage
genhtml coverage/lcov.info -o coverage/html
```
## Test Types
**Unit Tests:**
- Platform interface instantiation
- Method channel default instance verification
- Mock platform behavior testing
- File: `test/arc_test.dart`, `test/arc_method_channel_test.dart`
**Integration Tests:**
- Method channel handler testing
- Native plugin method call verification
- File: `android/src/test/java/com/xiarui/arc/ArcPluginTest.java`
**Widget Tests:**
- Basic widget rendering verification
- File: `example/test/widget_test.dart`
**E2E Tests:** Not used
## Common Patterns
**Async Testing:**
```dart
test('getPlatformVersion', () async {
expect(await arcPlugin.getPlatformVersion(), '42');
});
```
**Platform Instance Mocking:**
```dart
test('methodName', () async {
Arc arcPlugin = Arc();
MockArcPlatform fakePlatform = MockArcPlatform();
ArcPlatform.instance = fakePlatform; // Override instance
expect(await arcPlugin.method(), expectedResult);
});
```
**Setup/Teardown:**
```dart
setUp(() {
// Initialize test binding, set up mocks
TestWidgetsFlutterBinding.ensureInitialized();
});
tearDown(() {
// Clean up mocks
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(channel, null);
});
```
**Error Testing:**
Current tests do not explicitly test error scenarios. Recommended pattern for future:
```dart
test('throws on invalid params', () async {
expect(
() => arcPlugin.detectFaces(data: Uint8List(0), width: 0, height: 0),
throwsA(isA<PlatformException>()),
);
});
```
## Test Naming Convention
**Dart:**
- Simple descriptive names: `'getPlatformVersion'`
- Interpolated class names: `'$MethodChannelArc is the default instance'`
**Java:**
- Pattern: `methodName_scenario_expectedResult`
- Example: `onMethodCall_getPlatformVersion_returnsExpectedValue`
## Key Test Files
**Plugin Core Tests:**
- `test/arc_test.dart` - Platform interface and Arc class tests
- `test/arc_method_channel_test.dart` - Method channel implementation tests
**Example App Tests:**
- `example/test/widget_test.dart` - Basic widget test (template, needs updating)
**Native Tests:**
- `android/src/test/java/com/xiarui/arc/ArcPluginTest.java` - Android plugin tests
## Test Coverage Gaps
**Untested Methods:**
- `activeOnline()` - No test coverage
- `init()` - No test coverage
- `detectFaces()` - No test coverage
- `extractFaceFeature()` - No test coverage
- `compareFaceFeature()` - No test coverage
- `registerFaceFeature()` - No test coverage
- `registerFaceFeatureBatch()` - No test coverage
**Untested Scenarios:**
- Error handling (invalid parameters)
- Edge cases (null data, empty arrays)
- RGB liveness detection flow
- Face feature extraction and comparison
---
*Testing analysis: 2026-03-30*