61 lines
1.7 KiB
Cheetah
61 lines
1.7 KiB
Cheetah
---
|
|
description: "BLoC testing conventions for {{PROJECT_NAME}}"
|
|
alwaysApply: false
|
|
---
|
|
|
|
# BLoC Testing Standards — {{PROJECT_NAME}}
|
|
|
|
## Test pattern (bloc_test)
|
|
```dart
|
|
// {{TEST_PATTERN}}
|
|
|
|
void main() {
|
|
late AuthBloc authBloc;
|
|
late MockAuthRepository mockRepo;
|
|
|
|
setUp(() {
|
|
mockRepo = MockAuthRepository();
|
|
authBloc = AuthBloc(repository: mockRepo);
|
|
});
|
|
|
|
tearDown(() => authBloc.close());
|
|
|
|
group('AuthBloc', () {
|
|
blocTest<AuthBloc, AuthState>(
|
|
'emits [Loading, Authenticated] when login succeeds',
|
|
build: () {
|
|
when(() => mockRepo.login(any(), any()))
|
|
.thenAnswer((_) async => const Right(User(id: '1', email: 'test@test.com')));
|
|
return authBloc;
|
|
},
|
|
act: (bloc) => bloc.add(const AuthLoginRequested(email: 'test@test.com', password: 'pass')),
|
|
expect: () => [
|
|
const AuthLoading(),
|
|
isA<AuthAuthenticated>(),
|
|
],
|
|
);
|
|
|
|
blocTest<AuthBloc, AuthState>(
|
|
'emits [Loading, Failure] when login fails',
|
|
build: () {
|
|
when(() => mockRepo.login(any(), any()))
|
|
.thenAnswer((_) async => const Left(AuthError('Invalid credentials')));
|
|
return authBloc;
|
|
},
|
|
act: (bloc) => bloc.add(const AuthLoginRequested(email: 'bad', password: 'bad')),
|
|
expect: () => [
|
|
const AuthLoading(),
|
|
const AuthFailure('Invalid credentials'),
|
|
],
|
|
);
|
|
});
|
|
}
|
|
```
|
|
|
|
## Rules
|
|
- Use `mocktail` for mocking — never `mockito`
|
|
- Every BLoC test file: `test/features/[feature]/[feature]_bloc_test.dart`
|
|
- Coverage requirement: all state transitions must be tested
|
|
- Use `Given/When/Then` naming in test descriptions
|
|
- Test error paths as thoroughly as success paths
|