# 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()` **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()); }); 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 getPlatformVersion() => Future.value('42'); @override Future?> 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?> 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()), ); }); ``` ## 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*