5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Flutter x RiverpodアプリのWidgetテストでProviderScopeを用いて初期値をオーバーライドする方法

Last updated at Posted at 2022-10-05

Flutterアプリのテストでproviderに初期値を指定する方法

FlutterでRiverpodを使用するアプリのwidget_testをする際にproviderの初期値を設定して
特定のテストを実施しやすくする方法です。

サンプルアプリ作成

flutter createで生成されるカウンターアプリを例に見てみます。
今回 hooks_riverpod を使用してカウント数の状態管理にStateProviderを使い
カウントが10まで達したらカウントをしないアプリを作ったとします。

// カウントの状態管理をするStateProvider
final countStateProvider = StateProvider<int>((ref) => 0);

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends HookConsumerWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final counter = ref.watch(countStateProvider);
    return Scaffold(
      appBar: AppBar(
        title: const Text("Flutter Demo Home Page"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // カウントの上限を設定
          if (counter < 10) {
            ref.read(countStateProvider.state).state++;
          }
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

簡単なテスト作成

このアプリに対してのwidget_testを作っていきます。
まずはボタンがタップされてカウントが1増加し画面の表示が切り替わっていることのテスト

  testWidgets('Count Up test', (WidgetTester tester) async {
    await tester.pumpWidget(const ProviderScope(
      child: MyApp(),
    ));
    expect(find.text('0'), findsOneWidget);
    expect(find.text('1'), findsNothing);
    await tester.tap(find.byIcon(Icons.add));
    await tester.pump();
    expect(find.text('0'), findsNothing);
    expect(find.text('1'), findsOneWidget);
  });

やっていることは カウント数の表示の有無の確認、 ボタンのタップと画面切り替えの待ち処理
カウントが増加したことを確認です。

Providerに初期値を設定

では次にカウントが10まで達したら表示が切り替わらないことをテストします。
この時

await tester.tap(find.byIcon(Icons.add));

の処理を10回回してもいいですが流石に冗長ですのでもっと簡単にかつきれいに書いていきます。
やり方は簡単で ProviderScope で アプリ内のProviderの初期値をオーバーライドしてしまえば最初からカウントが10の状態からテストを始めることができます。

  testWidgets('Count limit test', (WidgetTester tester) async {
    await tester.pumpWidget(ProviderScope(
      // overrides を使用して countStateProvider の初期値を10に設定する
      overrides: [countStateProvider.overrideWithValue(StateController(10))],
      child: const MyApp(),
    ));
    expect(find.text('10'), findsOneWidget);
    await tester.tap(find.byIcon(Icons.add));
    await tester.pump();
    expect(find.text('10'), findsOneWidget);
    expect(find.text('11'), findsNothing);
  });

ProviderScopeoverrides プロパティの配列にオーバーライドするProviderとその値を渡してあげることで最初からカウントが10の状態でテストできます。(今回はStateProviderを使用しているため.overrideWithValue の引数には StateController を使っています。) .

この方法を使うことでテストの際にモック化されたモデルや外部通信のモック/フェイクを使って自動テストをすることができます。

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?