← スキル一覧に戻る

testing-patterns
by Kaakati
Enterprise-grade Rails development workflow with multi-agent orchestration, beads task tracking, and quality gates. Generic and portable across any Rails project.
⭐ 2🍴 0📅 2026年1月24日
SKILL.md
name: "Testing Patterns" description: "Unit, widget, integration, and golden test patterns with mocking strategies" version: "1.0.0"
Testing Patterns
Unit Tests (Domain & Data Layers)
Use Case Testing
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:dartz/dartz.dart';
class MockUserRepository extends Mock implements UserRepository {}
void main() {
late GetUser useCase;
late MockUserRepository mockRepository;
setUp(() {
mockRepository = MockUserRepository();
useCase = GetUser(mockRepository);
});
group('GetUser', () {
final tUser = User(
id: '1',
name: 'Test User',
email: 'test@example.com',
createdAt: DateTime(2024),
);
test('should return user when repository call is successful', () async {
// Arrange
when(() => mockRepository.getUser('1'))
.thenAnswer((_) async => Right(tUser));
// Act
final result = await useCase('1');
// Assert
expect(result, Right(tUser));
verify(() => mockRepository.getUser('1')).called(1);
verifyNoMoreInteractions(mockRepository);
});
test('should return ServerFailure when repository fails', () async {
// Arrange
when(() => mockRepository.getUser('1'))
.thenAnswer((_) async => Left(ServerFailure('Error')));
// Act
final result = await useCase('1');
// Assert
expect(result, isA<Left>());
verify(() => mockRepository.getUser('1')).called(1);
});
});
}
Repository Testing
class MockUserProvider extends Mock implements UserProvider {}
class MockUserLocalSource extends Mock implements UserLocalSource {}
class MockNetworkInfo extends Mock implements NetworkInfo {}
void main() {
late UserRepositoryImpl repository;
late MockUserProvider mockProvider;
late MockUserLocalSource mockLocalSource;
late MockNetworkInfo mockNetworkInfo;
setUp(() {
mockProvider = MockUserProvider();
mockLocalSource = MockUserLocalSource();
mockNetworkInfo = MockNetworkInfo();
repository = UserRepositoryImpl(
mockProvider,
mockLocalSource,
mockNetworkInfo,
);
});
group('getUser', () {
final tUserModel = UserModel(
id: '1',
name: 'Test',
email: 'test@example.com',
createdAt: DateTime(2024),
);
test('should return remote data when online', () async {
// Arrange
when(() => mockNetworkInfo.isConnected).thenAnswer((_) async => true);
when(() => mockProvider.fetchUser('1'))
.thenAnswer((_) async => tUserModel);
when(() => mockLocalSource.cacheUser(tUserModel))
.thenAnswer((_) async => {});
// Act
final result = await repository.getUser('1');
// Assert
verify(() => mockProvider.fetchUser('1'));
verify(() => mockLocalSource.cacheUser(tUserModel));
expect(result, Right(tUserModel.toEntity()));
});
test('should return cached data when offline', () async {
// Arrange
when(() => mockNetworkInfo.isConnected).thenAnswer((_) async => false);
when(() => mockLocalSource.getCachedUser('1'))
.thenAnswer((_) async => tUserModel);
// Act
final result = await repository.getUser('1');
// Assert
verify(() => mockLocalSource.getCachedUser('1'));
verifyNever(() => mockProvider.fetchUser('1'));
expect(result, Right(tUserModel.toEntity()));
});
});
}
Controller Testing
class MockGetUser extends Mock implements GetUser {}
void main() {
late UserController controller;
late MockGetUser mockGetUser;
setUp(() {
mockGetUser = MockGetUser();
controller = UserController(getUserUseCase: mockGetUser);
});
tearDown(() {
controller.dispose();
});
group('UserController', () {
final tUser = User(
id: '1',
name: 'Test',
email: 'test@example.com',
createdAt: DateTime(2024),
);
test('initial state should be empty', () {
expect(controller.user, null);
expect(controller.isLoading, false);
expect(controller.error, null);
});
test('should load user successfully', () async {
// Arrange
when(() => mockGetUser('1')).thenAnswer((_) async => Right(tUser));
// Act
await controller.loadUser('1');
// Assert
expect(controller.user, tUser);
expect(controller.isLoading, false);
expect(controller.error, null);
});
test('should handle error', () async {
// Arrange
when(() => mockGetUser('1'))
.thenAnswer((_) async => Left(ServerFailure('Error')));
// Act
await controller.loadUser('1');
// Assert
expect(controller.user, null);
expect(controller.isLoading, false);
expect(controller.error, isNotNull);
});
});
}
Widget Tests
void main() {
testWidgets('UserPage displays loading indicator', (tester) async {
// Arrange
final mockController = MockUserController();
when(() => mockController.isLoading).thenReturn(true);
when(() => mockController.user).thenReturn(null);
when(() => mockController.error).thenReturn(null);
Get.put<UserController>(mockController);
// Act
await tester.pumpWidget(
GetMaterialApp(home: UserPage()),
);
// Assert
expect(find.byType(CircularProgressIndicator), findsOneWidget);
// Cleanup
Get.delete<UserController>();
});
testWidgets('UserPage displays user data', (tester) async {
// Arrange
final tUser = User(
id: '1',
name: 'John Doe',
email: 'john@example.com',
createdAt: DateTime(2024),
);
final mockController = MockUserController();
when(() => mockController.isLoading).thenReturn(false);
when(() => mockController.user).thenReturn(tUser);
when(() => mockController.error).thenReturn(null);
Get.put<UserController>(mockController);
// Act
await tester.pumpWidget(
GetMaterialApp(home: UserPage()),
);
// Assert
expect(find.text('John Doe'), findsOneWidget);
expect(find.text('john@example.com'), findsOneWidget);
// Cleanup
Get.delete<UserController>();
});
testWidgets('UserPage displays error', (tester) async {
// Arrange
final mockController = MockUserController();
when(() => mockController.isLoading).thenReturn(false);
when(() => mockController.user).thenReturn(null);
when(() => mockController.error).thenReturn('Server error');
Get.put<UserController>(mockController);
// Act
await tester.pumpWidget(
GetMaterialApp(home: UserPage()),
);
// Assert
expect(find.text('Server error'), findsOneWidget);
expect(find.byIcon(Icons.error_outline), findsOneWidget);
// Cleanup
Get.delete<UserController>();
});
}
Integration Tests
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('User Flow Integration Tests', () {
testWidgets('complete user login flow', (tester) async {
// Start app
await tester.pumpWidget(MyApp());
await tester.pumpAndSettle();
// Navigate to login
await tester.tap(find.text('Login'));
await tester.pumpAndSettle();
// Enter credentials
await tester.enterText(find.byType(TextField).at(0), 'test@example.com');
await tester.enterText(find.byType(TextField).at(1), 'password');
await tester.pumpAndSettle();
// Submit
await tester.tap(find.text('Submit'));
await tester.pumpAndSettle();
// Verify navigation to home
expect(find.text('Home'), findsOneWidget);
});
});
}
Golden Tests
void main() {
testWidgets('UserCard golden test', (tester) async {
final tUser = User(
id: '1',
name: 'John Doe',
email: 'john@example.com',
createdAt: DateTime(2024),
);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: UserCard(user: tUser),
),
),
);
await expectLater(
find.byType(UserCard),
matchesGoldenFile('goldens/user_card.png'),
);
});
}
スコア
総合スコア
60/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
✓説明文
100文字以上の説明がある
+10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
レビュー
💬
レビュー機能は近日公開予定です