5
3

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 3 years have passed since last update.

下記環境でFlutterアプリを開発中です。

ツールなど バージョンなど
MacBook Air Early2015 macOS Mojave 10.14.5
Android Studio 3.6.1
Java 1.8.0_131
Flutter 1.12.13+hotfix.5
Dart 2.7.0

Imageのテストをしていて少しググったので、まとめておきます。
なお、Iconはfind.byIcon()で簡単にできるのでここでは割愛します。

AssetImage

byWidgetPredicateで、Imageであり、かつその中に持つimageメンバーがAssetImageであり、かつそのimage.keyNameが指定したasstesのパスと一致するか調べればテストできます。

サンプルコードは以下の通りです。
長いので、使い回しに便利になるようfindByAssetImage関数に出してあります。

void main(){
  /// 指定のpathを表示しているAssetImageを見つける
  Finder findByAssetImage(String path) {
    final finder = find.byWidgetPredicate((Widget widget) {
      if (widget is Image && widget.image is AssetImage) {
        final assetImage = widget.image as AssetImage;
        return assetImage.keyName == path;
      }
      return false;
    });
    return finder;
  }

  group('Imageのテスト', () {
    testWidgets('AssetImage', (WidgetTester tester) async {
      await tester
          .pumpWidget(MaterialApp(
          home: MyHomePage(),
        ),
      );

      expect(findByAssetImage('assets/home_bg.png'), findsOneWidget);
    });
  });
}

NetworkImage

AssetImageのテストをまねて、以下のコードを書いても、失敗します。

void main(){
    /// 指定のurlを表示しているNetworkImageを見つける
    Finder findByNetworkImage(String path) {
      final finder = find.byWidgetPredicate((Widget widget) {
        if (widget is Image && widget.image is NetworkImage) {
          final networkImage = widget.image as NetworkImage;
          return networkImage.url == path;
        }
        return false;
      });
      return finder;
    }

    group('Imageのテスト', () {
      testWidgets('Network Image', (WidgetTester tester) async {
          String path = 'https://hogehoge.com/sample.png';
          await tester.pumpWidget(
            MaterialApp(
              home: Image.network(path),
            ),
          );
          expect(findByNetworkImage(path), findsOneWidget);
      });
    });
  });

}

Image.network()で読み込んだImageがあると、実はウィジェットテストは失敗してしまいます。
必ず404が返ってきてしまうのです。
これはTesterの中でHttpClientがモック化されて何も通信しないようになっていて、そのせいのようです。

参考:
https://github.com/flutter/flutter/issues/21870
https://stackoverflow.com/questions/49166234/flutter-widget-tests-with-networkimage

で、これを解決するために、便利なライブラリを提供して下さっている方がいます。
(上記参考ページのStackoverflowで作者が回答していますw)

使い方はInstallingタブにあるとおりですが、まず、pubspec.yamlに以下の記述を追加します。

pubspec.yaml
dev_dependencies:
  # network image test
  image_test_utils: ^1.0.0

dev_dependencies:下に追加するのを間違えないで下さい。

次に、testWidget内のテストコードの記述を、provideMockedNetworkImagesで括ります。

void main(){
    /// 指定のurlを表示しているNetworkImageを見つける
    Finder findByNetworkImage(String path) {
...
    }

    group('Imageのテスト', () {
      testWidgets('Network Image', (WidgetTester tester) async {
        provideMockedNetworkImages(() async { // 追加
          String path = 'https://hogehoge.com/sample.png';
          await tester.pumpWidget(
            MaterialApp(
              home: Image.network(path),
            ),
          );

          expect(findByNetworkImage(path), findsOneWidget);
        }); // 追加
      });
    });
  });
}

これで画像自体はダミーを読み込みつつ、セットされたurlが意図通りかというテストは出来るようになります。

また、Imageのテストはしないけどページ内にHttpアクセスがあり自動的にキックされてしまうような実装の場合にも有用ですね。

参考サイト

[Flutter] Widget Test の逆引き Tips
https://qiita.com/sensuikan1973/items/161c8efa1a47d1ceb563

5
3
1

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
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?