🪶
初学者すぎてRiverpodでのDIが分からなかったのでメモ
概要
Flutter超初学者です。
RiverpodでDIする第一歩を個人的にメモ。
やってみた
pubspec.yamlにflutter_riverpodを追記
pubspec.yaml
dependencies:
flutter:
sdk: flutter
flutter_riverpod: ^2.3.4
動物の名前の文字列の配列を返すリポジトリのインターフェースを定義し、
そのインターフェースのプロバイダを定義(後にこのプロバイダに実装を注入する)
animal_i_repository.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
// インターフェースの型のProviderを定義
// 後に実際の実装を注入する
// 注入がされない場合は[UnimplementedError]をthrow
final animalRepositoryProvider = Provider<IAnimalRepository>(
(_) => throw UnimplementedError(),
);
// インターフェース
abstract class IAnimalRepository {
List<String> findAll();
}
インターフェースを実装(簡易的に配列をそのまま返すだけ)
animal_repository.dart
import 'package:riverpod_di/animal_i_repository.dart';
class AnimalRepository implements IAnimalRepository {
AnimalRepository();
List<String> findAll() {
return ['ゾウ', 'ライオン', 'キリン'];
}
}
ProviderScopeのoverridesで対象のプロバイダに実装を注入
(画面は動物名をListViewで並べるだけ)
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_di/animal_i_repository.dart';
import 'package:riverpod_di/animal_repository.dart';
void main() {
// ProviderScopeのoverridesで注入する
runApp(ProviderScope(overrides: [
animalRepositoryProvider.overrideWithValue(AnimalRepository()),
], child: MyApp()));
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
final animalsProvider = Provider((ref) {
final animalRepository = ref.watch(animalRepositoryProvider);
return animalRepository.findAll();
});
class HomePage extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final animals = ref.watch(animalsProvider);
return Scaffold(
appBar: AppBar(
title: const Text('DI demo'),
),
body: ListView.builder(
itemCount: animals.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(animals[index]),
);
}));
}
}
以下のような画面になりました!
これで第一歩は踏めているのか...??
WidgetTestでmockのリポジトリを注入してみます。
インターフェースを実装したmockリポジトリを作成し、pumpWidgetでの生成時に同じように注入します。
widget_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_di/main.dart';
import 'package:riverpod_di/animal_i_repository.dart';
void main() {
testWidgets('dummyデータが表示されるかのテスト', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(ProviderScope(overrides: [
animalRepositoryProvider.overrideWithValue(MockAnimalRepository()),
], child: MyApp()));
expect(find.text('dummyゾウ'), findsOneWidget);
expect(find.text('dummyライオン'), findsOneWidget);
expect(find.text('dummyキリン'), findsOneWidget);
});
}
// インターフェースを実装したモックのリポジトリ
class MockAnimalRepository implements IAnimalRepository {
MockAnimalRepository();
List<String> findAll() {
return ['dummyゾウ', 'dummyライオン', 'dummyキリン'];
}
}
テストも通りました。
✓ dummyデータが表示されるかのテスト
Exited
きっと色々間違っていたりするんだろうけど、一歩は踏めていると思うのでヨシ!!!
Discussion
✨✨✨✨✨✨