下記環境で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
に以下の記述を追加します。
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