📂

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

2025/03/01に公開

はじめに

テストでは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のモデル

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をモックします。

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

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

  ...
}

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

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

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

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

モックにスタブを設定する

testでスタブを作る時と同じくwhenでスタブを作ると反映されます。

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';

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

  
  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('モックのメソッドをタップ'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

注意点

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

まずはbuild.yamlに自動生成を許容するファイルを限定しておく必要があると思います。
誤って本番用のファイルに混入してしまうのを防ぐためです。
例えば以下のように具体的なファイルを指定する方法です。

targets:
  $default:
    builders:
      mockito|mockBuilder:
        generate_for:
          - test/**.dart
          - lib/debug/debug_screen.dart # <= 💡 ファイルまで指定する

その上で上記の例のようにdebug_screenだけに限定したとします。
このdebug_screenFlavorを使って開発環境のみ表示するように限定するなどにした方が良いでしょう。

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

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

終わりに

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

Discussion