6.8 KiB
6.8 KiB
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:
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.dartpattern (arc_test.dart,arc_method_channel_test.dart,widget_test.dart) - Java:
*Test.javapattern (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:
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:
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:
MockPlatformInterfaceMixinfrom plugin_platform_interface- Custom mock class implementing platform interface
Example:
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:
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 objectsverify(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:
@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:
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:
test('getPlatformVersion', () async {
expect(await arcPlugin.getPlatformVersion(), '42');
});
Platform Instance Mocking:
test('methodName', () async {
Arc arcPlugin = Arc();
MockArcPlatform fakePlatform = MockArcPlatform();
ArcPlatform.instance = fakePlatform; // Override instance
expect(await arcPlugin.method(), expectedResult);
});
Setup/Teardown:
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:
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 teststest/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 coverageinit()- No test coveragedetectFaces()- No test coverageextractFaceFeature()- No test coveragecompareFaceFeature()- No test coverageregisterFaceFeature()- No test coverageregisterFaceFeatureBatch()- 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