From flutter-skills
Implements unit, widget, and integration tests for a Flutter app. Use when ensuring code quality and preventing regressions through automated testing.
npx claudepluginhub gsmlg-dev/code-agent --plugin flutter-skillsThis skill uses the workspace's default tool permissions.
- [Core Testing Strategies](#core-testing-strategies)
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides MCP server integration in Claude Code plugins via .mcp.json or plugin.json configs for stdio, SSE, HTTP types, enabling external services as tools.
Balance your testing suite across three main categories to optimize for confidence, maintenance cost, dependencies, and execution speed.
Use unit tests to verify the correctness of a single function, method, or class under various conditions.
test or flutter_test package.Use widget tests (component tests) to ensure a single widget's UI looks and interacts as expected.
WidgetTester.Finder classes to locate widgets and Matcher constants to verify their existence and state.Use integration tests (end-to-end or GUI testing) to validate how individual pieces of an app work together and to capture performance metrics on real devices.
integration_test package as a dependency.Design your application for observability and testability. Ensure all components can be tested both in isolation and together.
Fake implementations of your repositories (e.g., FakeUserRepository) over using mocking libraries when testing ViewModels and Views to ensure well-defined inputs and outputs.When testing plugins, combine Dart tests with native platform tests to ensure full coverage across the method channel.
android/src/test/.example/ios/RunnerTests/ and example/macos/RunnerTests/.linux/test/ and windows/test/.Copy and track this checklist when implementing tests for a new architectural feature.
Fake implementations for any new Repositories or Services.Follow conditional logic based on the target platform when executing integration tests.
flutter test integration_test/app_test.dartchromedriver --port=4444flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart -d chromexvfb-run to provide a display environment.xvfb-run flutter test integration_test/app_test.dart -d linuxflutter build apk --debug and ./gradlew app:assembleAndroidTestDemonstrates testing a ViewModel using a Fake Repository.
import 'package:flutter_test/flutter_test.dart';
void main() {
group('HomeViewModel tests', () {
test('Load bookings successfully', () {
// Inject fake dependencies
final viewModel = HomeViewModel(
bookingRepository: FakeBookingRepository()..createBooking(kBooking),
userRepository: FakeUserRepository(),
);
// Verify state
expect(viewModel.bookings.isNotEmpty, true);
});
});
}
Demonstrates testing a View by pumping a localized widget tree with fake dependencies.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('HomeScreen tests', () {
late HomeViewModel viewModel;
late FakeBookingRepository bookingRepository;
setUp(() {
bookingRepository = FakeBookingRepository()..createBooking(kBooking);
viewModel = HomeViewModel(
bookingRepository: bookingRepository,
userRepository: FakeUserRepository(),
);
});
testWidgets('renders bookings list', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: HomeScreen(viewModel: viewModel),
),
);
// Verify UI state
expect(find.byType(ListView), findsOneWidget);
expect(find.text('Booking 1'), findsOneWidget);
});
});
}
Demonstrates a full end-to-end test using the integration_test package.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('end-to-end test', () {
testWidgets('tap on the floating action button, verify counter', (tester) async {
// Load app widget
await tester.pumpWidget(const MyApp());
// Verify initial state
expect(find.text('0'), findsOneWidget);
// Find and tap the button
final fab = find.byKey(const ValueKey('increment'));
await tester.tap(fab);
// Trigger a frame to allow animations/state to settle
await tester.pumpAndSettle();
// Verify updated state
expect(find.text('1'), findsOneWidget);
});
});
}