Use when writing or reviewing Flutter/Dart tests (unit, widget, golden), fixing flaky tests, adding coverage, or choosing between unit and widget tests.
Scanned 8/31/2026
Install to Claude Code
npx -y skills add evanca/flutter-ai-rules --skill testing --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Testing?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/evanca-testing)More formats (shields.io, HTML) on the badges page.
---
name: testing
description: "Use when writing or reviewing Flutter/Dart tests (unit, widget, golden), fixing flaky tests, adding coverage, or choosing between unit and widget tests."
license: MIT
---
# Testing Skill
Write effective, meaningful Flutter and Dart tests that catch real regressions.
## When to Use
Use this skill when:
* Writing unit tests for business logic, repositories, or utility classes.
* Writing widget tests for UI components.
* Reviewing existing tests for correctness and coverage.
* Fixing flaky or false-positive tests.
* Deciding between unit tests, widget tests, and integration tests.
---
## 1. Test Validity
Before writing or accepting a test, ask:
> **"Can this test actually fail if the real code is broken?"**
- Avoid tests that only confirm mocked/fake behavior without exercising real logic.
- Avoid tests that confirm behavior guaranteed by the language or standard library.
- Every test must be capable of catching a real regression.
```dart
// BAD — tests the mock, not real logic
test('should return user', () {
when(() => repo.getUser()).thenReturn(fakeUser);
expect(repo.getUser(), fakeUser); // Only proves the mock works
});
// GOOD — tests the cubit's state transitions driven by the mock
blocTest<UserCubit, UserState>(
'should emit loaded state when getUser succeeds',
build: () {
when(() => repo.getUser()).thenAnswer((_) async => fakeUser);
return UserCubit(repo);
},
act: (cubit) => cubit.fetchUser(),
expect: () => [
const UserState(status: UserStatus.loading),
UserState(status: UserStatus.loaded, user: fakeUser),
],
);
```
---
## 2. Structure
Always use `group()` in test files. Name the group after the **class under test**:
```dart
group('Counter', () {
late Counter counter;
setUp(() {
counter = Counter();
});
test('value should start at 0', () {
expect(counter.value, 0);
});
test('should increment value by 1', () {
counter.increment();
expect(counter.value, 1);
});
});
```
Rules:
- Use `setUp` for shared object creation; use `tearDown` for cleanup (closing streams, controllers).
- Keep each test focused on one behavior.
- Nest `group()` blocks for sub-features when a class has many methods.
---
## 3. Naming
Name test cases using **"should"** to describe expected behavior:
```dart
test('should emit updated list when item is added', () { ... });
test('should throw ArgumentError when input is negative', () { ... });
```
---
## 4. Unit Tests vs Widget Tests
| Type | Target | Tools |
|---|---|---|
| **Unit test** | Pure Dart logic, repositories, cubits/blocs | `test`, `bloc_test`, `mocktail` |
| **Widget test** | Individual widgets, UI behavior, navigation | `flutter_test`, `WidgetTester` |
Default to **unit tests** for business logic. Use **widget tests** when verifying UI rendering, gesture handling, or widget interaction.
---
## 5. Widget Test Patterns
```dart
testWidgets('should display error message on failure', (tester) async {
await tester.pumpWidget(
MaterialApp(
home: BlocProvider<LoginCubit>.value(
value: mockLoginCubit,
child: const LoginView(),
),
),
);
// Simulate failure state
whenListen(
mockLoginCubit,
Stream.fromIterable([const LoginState(status: LoginStatus.failure, errorMessage: 'Invalid')]),
initialState: const LoginState(),
);
await tester.pump();
expect(find.text('Invalid'), findsOneWidget);
});
```
Rules:
- Wrap widgets in `MaterialApp` (or the app's root widget) to provide `MediaQuery`, `Directionality`, etc.
- Use `pump()` for a single frame or `pumpAndSettle()` when animations must complete.
- Prefer `find.byKey` over `find.text` for widgets that may have localized or dynamic text.
---
## 6. Mocking Best Practices
- Use `mocktail` for mocks (no code generation required).
- Call `registerFallbackValue()` in `setUpAll` for custom types passed to `any()`.
- Mock at the repository boundary, not at the HTTP/database layer.
```dart
class MockAuthRepository extends Mock implements AuthRepository {}
void main() {
setUpAll(() {
registerFallbackValue(FakeLoginRequest());
});
// ... tests
}
```
---
## 7. Test File Organization
```
test/
feature_a/
cubit/
feature_a_cubit_test.dart
view/
feature_a_view_test.dart
model/
feature_a_model_test.dart
```
- Mirror the `lib/` folder structure under `test/`.
- One test file per source file.
- Name test files `<source_file>_test.dart`.
No comments yet. Be the first to comment!