testing
Writes unit and widget tests for blocs, repositories, and screens using bloc_test + mocktail
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Writes unit and widget tests for blocs, repositories, and screens using bloc_test + mocktail
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Handles cross-feature BusEvent communication with EventBusManager in the Flutter base template
Implements BLoC state management using AppBlocBase, an abstract State hierarchy, and a freezed _StateData
Builds the data layer with Freezed DTOs, Retrofit clients, hive_ce local stores, and repositories wired through injectable
Reviews UI-layer changes — screens, blocs, widgets, routes — against the template's StateBase + AppBlocBase + fl_theme conventions
Adds and updates app strings through the CSV → ARB → generated localizations workflow
Scaffolds a new feature module under apps/main/lib/presentation/modules using the bundled module generator
| name | testing |
| description | Writes unit and widget tests for blocs, repositories, and screens using bloc_test + mocktail |
| license | MIT |
| compatibility | all |
| metadata | {"audience":"flutter-developers","framework":"flutter","pattern":"testing"} |
Tests live next to the package they cover:
apps/main/test/ # app-level tests
core/test/ # core-level tests
modules/data_source/test/
plugins/<plugin>/test/
A common shape inside apps/main/test/:
test/
├── unit/
│ ├── bloc/
│ ├── domain/
│ └── data/
├── widget/
└── helpers/
flutter test # current package
flutter test test/unit/bloc/foo_bloc_test.dart
make coverage_main # coverage on apps/main, via coverage.sh
There is no make test / make analyze aggregate target — invoke flutter test and flutter analyze (or dart analyze) per package as needed.
Use bloc_test for sequence assertions and mocktail for collaborators.
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
class _MockUsecase extends Mock implements FeatureUsecase {}
void main() {
late _MockUsecase usecase;
late FeatureBloc bloc;
setUp(() {
usecase = _MockUsecase();
bloc = FeatureBloc(null, usecase);
});
tearDown(() => bloc.close());
group('FeatureBloc', () {
test('initial state is FeatureInitial with empty data', () {
expect(bloc.state, isA<FeatureInitial>());
expect(bloc.state.data.detail, isNull);
});
blocTest<FeatureBloc, FeatureState>(
'GetFeatureEvent loads detail and stays in FeatureInitial',
build: () {
when(() => usecase.getById('1'))
.thenAnswer((_) async => Item(id: '1', name: 'A'));
return bloc;
},
act: (b) => b.add(GetFeatureEvent('1')),
expect: () => [
isA<FeatureInitial>().having((s) => s.detail?.id, 'detail.id', '1'),
],
);
});
}
Note: this template's blocs use abstract class state hierarchies, not freezed unions, so assert with isA<FeatureInitial>() plus having(...) rather than equality on a sealed union.
class _MockApi extends Mock implements UserApiClient {}
void main() {
late _MockApi api;
late UserRepositoryImpl repo;
setUp(() {
api = _MockApi();
repo = UserRepositoryImpl(api);
});
test('getUser delegates to api client', () async {
final user = UserModel(id: '1', name: 'A');
when(() => api.getUser('1')).thenAnswer((_) async => user);
expect(await repo.getUser('1'), user);
verify(() => api.getUser('1')).called(1);
});
}
Wrap the screen in the same providers it gets in production: a BlocProvider (with a mocked bloc) and MaterialApp.router or a plain MaterialApp with Localizations if your widget reads context.l10n.
class _MockBloc extends MockBloc<FeatureEvent, FeatureState>
implements FeatureBloc {}
void main() {
late _MockBloc bloc;
setUp(() => bloc = _MockBloc());
Widget pump(Widget child) => MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: BlocProvider<FeatureBloc>.value(value: bloc, child: child),
);
testWidgets('shows empty state when items is empty', (tester) async {
when(() => bloc.state).thenReturn(
FeatureInitial(data: const _StateData()),
);
await tester.pumpWidget(pump(const FeatureScreen()));
expect(find.byType(EmptyData), findsOneWidget);
});
}
For interactions, drive a real bloc through the actions extension instead of mocking — it catches more bugs.
Fallback values for any value-typed argument matchers (registerFallbackValue(...)).verifyNever/verifyInOrder over loose verify.Mock instances between tests — recreate in setUp.lib/.../foo_bloc.dart ↔ test/unit/bloc/foo_bloc_test.dart).tearDown.mocktail consistently across the file.flutter test passes locally before commit.state == FeatureLoaded(...) — equality is reference-based on these abstract state classes; use isA<>().having(...).registerFallbackValue for typed arguments and getting cryptic mocktail errors.MaterialApp ancestor; localizations and themes blow up.