【Flutter】テストだけじゃない！libでもmockitoを活用する方法


:::note info
本記事は以下で投稿した内容と同じです。
:::

https://zenn.dev/harx/articles/5e1e7af2173f78

## はじめに

テストではmockitoを使ってクラスのモックとスタブを作成することがよくあると思います。

https://pub.dev/packages/mockito

しかし、実はこのmockitoはテストファイル以外にも使えることを最近知ったのでご紹介したいと思います。

### 記事の対象者

- lib配下でもmockitoを使ってみたい方
- ひとまず画面でモックデータを使ってUIを構築したい方

### 記事を執筆時点での筆者の環境

```
[✓] Flutter (Channel stable, 3.27.1, on macOS 15.1 24B2082 darwin-arm64, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 16.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2024.2)
[✓] VS Code (version 1.96.2)
```

## モック関連の準備

### Userのモデル

```dart
class User {
  User({
    required this.name,
    required this.email,
    required this.password,
  });

  final String name;
  final String email;
  final String password;
}

```

### モック対象のクラス または　パッケージ

今回はSharedPreferencesを例にしますのでインストールしておきます。

https://pub.dev/packages/shared_preferences

### mockitoのインストール
こちらもお忘れなく

https://pub.dev/packages/mockito


## モックの作成

### lib内でモックを作成する
テストの時と同様にモックを使用したいファイル内にモックを作成していきます。
今回は`User`モデルと`SharedPreferences`をモックします。

```dart
import 'package:flutter/material.dart';
import 'package:mockito/annotations.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:simple_base/domains/user.dart';

@GenerateNiceMocks([
  MockSpec<SharedPreferences>(),
  MockSpec<User>(),
])
class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  ...
}
```

### build.yamlを設定して自動生成する

このままbuild_runnerを走らせてもモックを生成してくれません。
なのでルートディレクトリ直下にbuild.yamlを作成して以下のように記入してください。

```yaml
targets:
  $default:
    builders:
      mockito|mockBuilder:
        generate_for:
          - test/**.dart
          - lib/**.dart

```
これによって、testディレクトリ配下だけではなく、libディレクトリ配下でも自動生成が有効になります。
自動生成を走らせてみてください。

### モックにスタブを設定する
testでスタブを作る時と同じく`when`でスタブを作ると反映されます。

```dart
import 'package:flutter/material.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:simple_base/domains/user.dart';
import 'package:simple_base/main.mocks.dart';

@GenerateNiceMocks([
  MockSpec<SharedPreferences>(),
  MockSpec<User>(),
])
class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final user = MockUser();
    when(user.name).thenReturn('John Doe');
    when(user.email).thenReturn('john@example.jp');
    when(user.password).thenReturn('password');

    return Scaffold(
      body: SafeArea(
        child: Center(
          child: Column(
            spacing: 20,
            children: [
              Text(
                'Name: ${user.name} \nEmail: ${user.email} '
                '\nPassword: ${user.password}',
              ),
              ElevatedButton(
                onPressed: () {
                  final prefs = MockSharedPreferences();
                  when(prefs.getString('key')).thenReturn('モックの値を取得しました');
                  final value = prefs.getString('key');
                  if (value == null) return;

                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text(value)),
                  );
                },
                child: const Text('モックのメソッドをタップ'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

```

![mockito_in_lib.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3058346/02c7e011-88fe-4285-af94-75609a1201bd.gif)

## 注意点

ただのサンプルプロジェクトならこれでいいのですが、リリース前提のプロジェクトではもう少し慎重に扱った方が良いでしょう。

まずはbuild.yamlに自動生成を許容するファイルを限定しておく必要があると思います。
誤って本番用のファイルに混入してしまうのを防ぐためです。
例えば以下のように具体的なファイルを指定する方法です。
```yaml
targets:
  $default:
    builders:
      mockito|mockBuilder:
        generate_for:
          - test/**.dart
          - lib/debug/debug_screen.dart # <= 💡 ファイルまで指定する
```
その上で上記の例のように`debug_screen`だけに限定したとします。
この`debug_screen`は`Flavor`を使って開発環境のみ表示するように限定するなどにした方が良いでしょう。

開発環境の分け方は以下で解説しています。

https://zenn.dev/harx/articles/5e376198cd9b4a

## 終わりに

通常、mockito はテスト環境で使われることが多いですが、
デバッグや開発時のモックデータの取り扱いが簡単になります。
この方法をうまく活用することで、より柔軟にモックデータを扱いながら開発を進めることができます。
ぜひ試してみてください！