😇
riverpod+flutter テスト中でのstateの取得方法
riverpodを使っているときのユニットテスト・ウィジェットテストの書き方にハマったのでメモします。
ここではStateNotifierを使っているテスト中にstateの中身を比較する例を書いています。
ウィジェットテストでのstateの取得方法
// BuildContextを取得
final BuildContext context = tester.element(find
.byWidgetPredicate((Widget widget) => widget is SomeScreen));
// ProviderContainerを取得
final container = ProviderScope.containerOf(context);
// ProviderContainerからproviderをreadしてsomeStateを取得
container.read(someProvider);
単体テストでのstateの取得方法
// ProviderContainerを設定
final target = ProviderContainer(
overrides: [
// テスト初期値設定
someStateProvider.overrideWithValue(
SomeStateNotifier(
...
),
),
],
);
// ProviderContainerからproviderをreadしてsomeStateを取得
expect(container.read(emailChangeProvider);
実装&テストの例
実装部分
@freezed
class SomeState with _$SomeStateState {
const SomeStateState._();
factory SomeStateState({
@Default('') String someField1,
@Default(0) int someField2,
}) = _SomeState;
}
final someProvider =
StateNotifierProvider<SomeStateNotifier, SomeState>(
(ref) => SomeStateNotifier(
someState: SomeState(),
),
);
class SomeStateNotifier extends StateNotifier<SomeState> {
SomeStateNotifier({required SomeState someState})
: super(someState);
void onSomefield1Changed(String someField1) {
state = state.copyWith(someField1: someField1);
}
}
class SomeScreen extends ConsumerWidget {
SomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final someNotifier = ref.watch(someProvider.notifier);
final someState = ref.watch(emailChangeProvider);
return Scaffold(
appBar: AppBar(
title: Text(
someState.field1,
style: Theme.of(context).textTheme.headline6,
),
),
....
}
}
テスト内でのsomeStateの値比較
void main() {
// ウィジェットテスト
testWidgets('someField', (WidgetTester tester) async {
final target = ProviderScope(
overrides: [
// テスト初期値設定
someStateProvider.overrideWithValue(
SomeStateNotifier(
someState: SomeState(
field1: 'field1',
field2: 'field2',
),
),
),
],
child: MaterialApp(
home: SomeScreen(),
),
);
//widget生成
await tester.pumpWidget(
target,
);
await tester.pumpAndSettle();
// BuildContextを取得
final BuildContext context = tester.element(find
.byWidgetPredicate((Widget widget) => widget is SomeScreen));
// ProviderContainerを取得
final container = ProviderScope.containerOf(context);
// ProviderContainerからproviderをreadしてsomeStateを取得
expect(container.read(someProvider).field1, field1);
});
statenotifierのユニットテスト
test('field1を受け取ってstateを更新する', () {
const field1 = 'test@example.com';
// ProviderContainerを設定
final target = ProviderContainer(
overrides: [
// テスト初期値設定
someStateProvider.overrideWithValue(
SomeStateNotifier(
someState: SomeState(
field1: 'field1',
field2: 'field2',
),
),
),
],
);
target.read(someStateProvider.notifier).onSomefield1Changed(field1);
// ProviderContainerからproviderをreadしてsomeStateを取得
expect(container.read(emailChangeProvider).newEmail, field1);
});
}
Discussion