| name | dart-add-unit-test |
| description | Write unit tests with mocking and coverage analysis for pure Dart projects and CLI apps. Use when testing business logic, generating mocks with Mockito or mocktail, or measuring test coverage. |
| metadata | {"platforms":"dart","languages":"dart","category":"testing"} |
Dart Testing Suite
Contents
Unit Testing
Utilize package:test as the standard testing library for Dart CLI and backend applications.
- Organize test files to mirror the
lib directory structure. Append _test.dart to test files.
- Group related tests using the
group() function.
- Use
setUp() and tearDown() for shared test state.
- Write pure logic inside Domain/BLoC and extract to static pure functions for 100% unit test coverage.
- Use string interpolation for test group names:
group('$ClassName', ...)
- Structure each test using the Arrange-Act-Assert (Given-When-Then) convention:
- Arrange: Set up mocks, create instances, prepare input data.
- Act: Call the method under test.
- Assert: Verify the output or side effects.
- Separate setup from verification to keep tests readable and maintainable.
Mocking Dependencies
mocktail vs mockito Decision
| Criteria | mocktail (Recommended) | mockito |
|---|
| Code generation | Not needed | Requires build_runner |
| Setup speed | Fast (extend Mock) | Slower (annotation + codegen) |
| Null safety | Full support | Full support |
| API style | when(() => mock.method()) | when(mock.method()) |
| Best for | Most projects, fast iteration | Large projects with complex APIs |
Rule: Default to mocktail (no codegen, faster setup). Use mockito only when you need @GenerateNiceMocks for complex APIs with many overloads.
mocktail Setup (Recommended)
import 'package:mocktail/mocktail.dart';
// Create mock — no code generation needed
class MockUserRepository extends Mock implements UserRepository {}
void main() {
late MockUserRepository mockRepo;
setUp(() {
mockRepo = MockUserRepository();
});
test('fetches user successfully', () {
// Arrange
when(() => mockRepo.getUser('1'))
.thenAnswer((_) async => const User(id: '1', name: 'Alice'));
// Act
final user = await mockRepo.getUser('1');
// Assert
expect(user.name, 'Alice');
verify(() => mockRepo.getUser('1')).called(1);
});
}
mockito Setup (Code-Gen)
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
@GenerateNiceMocks([MockSpec<UserRepository>()])
import 'user_test.mocks.dart'; // Generated by: dart run build_runner build
Verification APIs
| API | Purpose |
|---|
verify(() => mock.method()).called(1) | Assert method was called exactly once |
verifyNever(() => mock.method()) | Assert method was never called |
verifyNoMoreInteractions(mock) | Assert no unchecked interactions remain |
verifyInOrder([...]) | Assert methods were called in specific order |
reset(mock) | Clear all stubs and interactions |
Registering Fallback Values
For methods with custom types as parameters:
setUpAll(() {
registerFallbackValue(const User(id: '0', name: 'fallback'));
});
Test Coverage
- Target 100% logic coverage for domain models and business logic.
- Run coverage with
dart test --coverage=coverage or flutter test --coverage.
- See
dart-coverage skill for detailed LCOV/HTML report generation.
Workflow: Testing Execution
Follow this sequential workflow when testing a Dart feature. Copy the checklist to track progress.
Task Progress