【Flutter】Golden Testを用いた複数デバイス・解像度におけるデザインのリグレッションテスト

こんにちは、株式会社Pentagonでアプリ開発をしている山崎です!

この記事では、GoldenTestをする方法について説明します。

GoldenTestとは、Widgetテストのためのツールとなります。
スクリーンショットを最初に作り、その後修正し、テストを実行し、最初に作ったスクリーンショットと比較し、変更点があった場合はテスト失敗となります。変更点がない場合は、テスト成功となります。

GoldenTestをすることにより、UI上のデグレを防ぐことや、各端末サイズのデザインを一括で確認することができるようになります。

GoldenTestの使い方としては、UI以外のエラー修正やリファクタリング後にUIが変更されていないか確認するために使用したり、異なる端末サイズ毎にスクリーンショットを作成することができるので、小さい端末で文字が見切れていないかなど確認するのに使用することができると思います。

下の画像のタイトルに注目してください。 右の2つの端末画像でタイトルが見切れてます。このようなことを1つのコマンドを実行するだけで確認することができます。

複数画面を各端末毎にビルドすることなく、一括で確認したい人にとって役立つ内容となっています。

【こんな人に読んで欲しい】

  • 修正やリファクタリング後にUI上のデグレを起こしたくない人
  • GoldenTestを試したい人
  • 複数画面を一括で確認したい人

【この記事を読むメリット】

  • GoldenTestのやり方が分かる
  • GoldenTestで複数の画面サイズを設定するやり方が分かる

【結論】

GoldenTestをすることによって、端末ごとにビルドして確認する必要がなくなり、一括でさまざまな端末サイズの画面を確認することができるので、時間と手間を省くことができます。
この機会にGoldenTestを取り入れてみてはいかがでしょうか!

動作イメージ

目次

パッケージのインストール

最初に、pubspec.yamlに今回使用するパッケージを入力し、保存します。

dependencies:
  flutter:
    sdk: flutter
  golden_toolkit: ^0.15.0
  flutter_riverpod: ^2.3.6

ターミナルに下記のコマンドを入力し、パッケージをインストールします。

flutter pub get

フォント設定とアプリの作成

フォントの設定しない場合、Ahemというテスト用フォントが使用されるため、文字が四角などで表示され、正しく表示されません。


1.使用するttfファイルをassets/fonts/配下に配置してください。

2.pubspec.yamlのフォント設定をします。

fonts:
    - family: mukasi
      fonts:
        - asset: assets/fonts/gomarice_mukasi_mukasi.ttf

3.main関数にフォントの設定をします。

main.dart

import 'package:flutter/material.dart';
import 'package:hello/FirstPage.dart';

Future<void> main() async {
  runApp(
    MaterialApp(
      theme: ThemeData(
        fontFamily: 'mukasi',
      ),
      home: const FirstPage(),
    ),
  );
}

4.FirstPageを作成します。

FirstPage.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class FirstPage extends ConsumerWidget {
  const FirstPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Text("サンプルアプリ画面"),
      ),
      body: const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Text(
              '1行目',
              style: TextStyle(fontSize: 50),
            ),
            Text(
              '2行目',
              style: TextStyle(fontSize: 50),
            )
          ],
        ),
      ),
    );
  }
}

テストの作成

1.test/配下に「xxxxx_test.dart」という名前でファイルを作成してください。(xxxxxは自由です。今回はFirstPage_test.dartという名前で作成しました。)

2.テストコード作成

FirstPage_test.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:golden_toolkit/golden_toolkit.dart';
import 'package:hello/FirstPage.dart';

Future<void> main() async {
  // テスト環境の初期化
  TestWidgetsFlutterBinding.ensureInitialized();

  //使用する日本語フォントを読み込む
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:golden_toolkit/golden_toolkit.dart';
import 'package:hello/FirstPage.dart';

Future<void> main() async {
  // テスト環境の初期化
  TestWidgetsFlutterBinding.ensureInitialized();

  //フォントを読み込む
  final binary = rootBundle.load('assets/fonts/gomarice_mukasi_mukasi.ttf');
  final loader = FontLoader('mukasi')..addFont(binary);
  await loader.load();
  await loadAppFonts();

  testGoldens(
    'description',
    (tester) async {
      final builder = DeviceBuilder()
        // キャプチャしたいデバイスサイズと解像度を指定する
        ..overrideDevicesForAllScenarios(
          devices: [
            const Device(
              name: 'iPhone 14 Pro Max',
              size: Size(429, 928),
              devicePixelRatio: 3,
            ),
            const Device(
              name: 'iPhone 14 Plus',
              size: Size(428, 926),
              devicePixelRatio: 3,
            ),
            const Device(
              name: 'iPhone 14',
              size: Size(390, 844),
              devicePixelRatio: 3,
            ),
            const Device(
              name: 'iphoneSE',
              size: Size(375, 667),
              devicePixelRatio: 2,
            )
          ],
        )
        // どの画面をテストするか指定する、かつフォントを指定する
        ..addScenario(
            widget: MaterialApp(
              debugShowCheckedModeBanner: false,
              theme: ThemeData(
                fontFamily: 'mukasi',
              ),
              home: const FirstPage(),
            ),
            name: 'ScenarioName');
      // ビルドする
      await tester.pumpDeviceBuilder(builder);
      //事前にキャプチャされた画像と現在の画面と一致するかどうかを検証する
      await screenMatchesGolden(tester, 'goldenTestName');
    },
  );
}

テストの実行

1.ターミナルで下記のコマンドを実行して、キャプチャ画像を作成します。

flutter test --update-goldens

test/goldensというフォルダが作成され、その中にキャプチャ画像も作成されます。

2.ターミナルで下記のコマンドを入力して、テストを実行します。

flutter test 

テストが通れば「 All tests passed! 」と表示されます。

次に、FirstPage.dartを変更してテストを実行します。

テキストの「2行目」を削除します。

FirstPage.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class FirstPage extends ConsumerWidget {
  const FirstPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Text("サンプルアプリ画面"),
      ),
      body: const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Text(
              '1行目',
              style: TextStyle(fontSize: 50),
            ),
          ],
        ),
      ),
    );
  }
}

その後、ターミナルに下記のコマンドを入力し、再びテストを実行します。

flutter test 

すると「Some tests failed. 」とターミナルに表示されテストが失敗します。

それと同時にtest/failuresフォルダが作成され、さらにその中に4つpngファイルが作成されます。

goldenTestName_masterImage.pngは、最初にキャプチャした画像です。

goldenTestName_testImage.pngは、現在のキャプチャ画像です。

goldenTestName_isolatedDiff.pngは、差分を表示した画像です。

goldenTestName_maskedDiff.pngは、最初のキャプチャ画像との差分を表示した画像です。

まとめ

GoldenTestを使用すれば一括で、さまざまな端末サイズの画像を表示し確認することができます。
この機会に一度試してみてはいかがでしょうか?

おまけ

Flutterに関する知識を深めたい方には、『Flutterの特徴・メリット・デメリットを徹底解説』という記事がおすすめです。

この記事では、Flutter アプリ開発の基本から、flutter とは何か、そして実際のflutter アプリ 事例を通じて、その将来性やメリット、デメリットまで詳しく解説しています。
Flutterを使ったアプリ開発に興味がある方、またはその潜在的な可能性を理解したい方にとって、必見の内容となっています。

ぜひ一度ご覧ください。

採用情報はこちら
目次