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