Agent skill

flutter-tester

Use when creating, writing, fixing, or reviewing tests in a Flutter project. Covers unit tests, widget tests, integration tests, Riverpod provider testing, and Mockito mocking. Provides Given-When-Then patterns, layer isolation strategies, and test setup for GetIt, SharedPreferences, and FakeDatabase.

Stars 27
Forks 5

Install this agent skill to your Project

npx add-skill https://github.com/Harishwarrior/flutter-claude-skills/tree/main/flutter-tester

Metadata

Additional technical details for this skill

author
harish
version
1.0.0

SKILL.md

Flutter Tester

Overview

Test each architectural layer in isolation using Given-When-Then structure. Always test both success and error paths. Never mock providers — override their dependencies instead.

Reference Files

Load the relevant file based on what you're testing:

What you're testing Reference file
Repository, DAO, Service logic references/layer_testing_patterns.md
Widget UI, interactions, dialogs, navigation references/widget_testing_guide.md
Riverpod provider state, mutations, lifecycle references/riverpod_testing_guide.md

Core Principles

1. Layer Isolation

Test each layer against its own mocked dependencies:

Layer What to test What to mock
Repository Data coordination between sources DAOs, APIs, Logger
DAO Database CRUD operations Use real in-memory DB, mock Logger
Provider State management and transitions Services, Repositories
Service Business logic and workflows Repositories, Network clients
Widget UI behaviour and interactions Provider dependencies (via overrides)

2. Given-When-Then Structure

dart
test('Given valid data, When fetchUsers called, Then returns user list', () async {
  // Arrange (Given)
  when(mockDAO.fetchAll()).thenAnswer((_) async => expectedUsers);

  // Act (When)
  final result = await repository.fetchUsers();

  // Assert (Then)
  expect(result, equals(expectedUsers));
  verify(mockDAO.fetchAll()).called(1);
});

3. Test Organisation

dart
group('UserRepository', () {
  group('fetchUsers', () {
    setUp(() { /* init mocks, register with GetIt */ });
    tearDown(() => GetIt.I.reset()); // Always reset GetIt

    test('Given success ... When ... Then ...', () { });
    test('Given error  ... When ... Then ...', () { });
  });
});

Standard Test Setup

Generate Mocks

dart
@GenerateMocks([IUserDAO, IUserAPI, ILogger])
void main() { ... }

Run dart run build_runner build after modifying @GenerateMocks.

Register with GetIt

dart
setUp(() {
  mockDAO = MockIUserDAO();
  mockLogger = MockILogger();
  GetIt.I
    ..registerSingleton<IUserDAO>(mockDAO)
    ..registerSingleton<ILogger>(mockLogger);
});

tearDown(() => GetIt.I.reset()); // Critical — always reset

Fakes vs Mocks

  • Fakes (class FakeLogger extends ILogger) — silent stubs; use when you don't need to verify calls
  • Mocks (MockILogger) — use when you need when(), verify(), or thenThrow()

Quick Reference

Scenario Key pattern
Test a repository Mock DAO + API → inject into repository constructor
Test a DAO FakeDatabase or openInMemoryDatabase() in setUp, delete table in tearDown
Test a Riverpod provider createContainer(overrides: [serviceProvider.overrideWith(...)])
Test a widget Set screen size, use find.byKey(), call pumpAndSettle()
Test a loading state Use Completer, pump() to assert loading, complete, pump() again
Test platform-specific UI debugDefaultTargetPlatformOverride = TargetPlatform.iOS — reset after
Test GoRouter navigation FakeGoRouter + MockGoRouterProvider

Running Tests

bash
flutter test --coverage                       # All tests with coverage
flutter test test/path/to/test.dart           # Specific file
flutter test --plain-name "Given valid data"  # Filter by name
genhtml coverage/lcov.info -o coverage/html   # Generate HTML coverage report
# Prefix any command with `fvm` if using Flutter Version Manager

Common Mistakes

Mistake Fix
Mocking a provider directly Override its dependencies: provider.overrideWith(...)
Missing GetIt.I.reset() in tearDown Tests pollute each other — always reset
await Future.delayed() in tests Use await tester.pumpAndSettle() or Completer instead
Finding widgets by text string Use find.byKey(const Key('name')) — stable across text changes
No screen size in widget tests Add tester.view.physicalSize = const Size(1000, 1000)
Not resetting debugDefaultTargetPlatformOverride Set to null at the end of the test
tearDown() without a lambda Write tearDown(() async { ... }) not tearDown() async { ... }

Test Checklist

Setup & Mocking:

  • Dependencies mocked (not providers)
  • SharedPreferences mocked if used
  • GetIt.I.reset() in tearDown
  • Streams closed in tearDown
  • Controllers disposed in tearDown

Widget Tests:

  • Keys added to source widgets and used in find.byKey()
  • Screen size set (physicalSize + devicePixelRatio)
  • Platform overrides reset (debugDefaultTargetPlatformOverride = null)
  • Navigation verified if applicable

Test Coverage:

  • Success and failure paths covered
  • Edge cases tested (null, empty, max values)
  • Loading and error states tested
  • Async handled correctly (no Future.delayed)

Code Quality:

  • Given-When-Then naming used
  • verify() or verifyNever() where appropriate
  • Tests are isolated and deterministic

Expand your agent's capabilities with these related and highly-rated skills.

Harishwarrior/flutter-claude-skills

owasp-mobile-security-checker

Use when performing security audits, vulnerability assessments, or compliance checks on Flutter or mobile applications. Covers OWASP Mobile Top 10 (2024) — hardcoded secrets (M1), insecure storage (M9), weak cryptography (M10), network issues (M5), and 6 more categories with automated scanners and remediation guidance.

27 5
Explore
mattpocock/skills

setup-pre-commit

Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.

111,310 9,758
Explore
mattpocock/skills

obsidian-vault

Search, create, and manage notes in the Obsidian vault with wikilinks and index notes. Use when user wants to find, create, or organize notes in Obsidian.

111,310 9,758
Explore
mattpocock/skills

git-guardrails-claude-code

Set up Claude Code hooks to block dangerous git commands (push, reset --hard, clean, branch -D, etc.) before they execute. Use when user wants to prevent destructive git operations, add git safety hooks, or block git push/reset in Claude Code.

111,310 9,758
Explore
mattpocock/skills

edit-article

Edit and improve articles by restructuring sections, improving clarity, and tightening prose. Use when user wants to edit, revise, or improve an article draft.

111,310 9,758
Explore
mattpocock/skills

scaffold-exercises

Create exercise directory structures with sections, problems, solutions, and explainers that pass linting. Use when user wants to scaffold exercises, create exercise stubs, or set up a new course section.

111,310 9,758
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results