person t-kobayashi

Flutterでユニットテストとウィジェットテストを追加した際の手順

calendar_today 2021年05月20日 update 2021年05月20日
Facebook Twitter LINE はてなブックマーク Pocket

ユニットテストとウィジェットテストを追加した際に発生したエラーとその解消を記載します。

ユニットテストの導入

testパッケージのサイトの指示に従い、下記のようにバージョンを指定してユニットテスト用のパッケージをpubspec.yamlに追加します。

dev_dependencies:
  test: ^1.16.8

以下を実行すると下記のようなエラーが発生しました。

flutter pub get

結果

Because no versions of test match >1.16.8 <2.0.0 and test 1.16.8 depends on test_api 0.3.0, test ^1.16.8 requires test_api 0.3.0.

And because every version of flutter_test from sdk depends on test_api 0.2.19, test ^1.16.8 is incompatible with flutter_test from sdk.

So, because canton_tree depends on both flutter_test any from sdk and test ^1.16.8, version solving failed.

これは、dev_dependenciesにもともと含まれていた下記のウィジェットテスト用のパッケージが依存するtest_apiと、今回追加したtestパッケージが依存するtest_apiのバージョンが異なるため、解決できない競合が発生しているということのようです。

解決策

競合が発生しないバージョンのtestパッケージに変更すればよいのですが、下記のようにバージョンをしていしないことで自動的に解決してくれるということがわかったので、ここに下記のように記載します。

dev_dependencies:
  flutter_test:
    sdk: flutter
  test: 

以上でこちらのページで紹介されているユニットテストが実行可能になりました。

ウィジェットテストの導入

TitleScreenウィジェットが表示されることをテストするために、testフォルダにtitle_screen_widget_test.dartというファイルを作成し、以下のコードを書きます。

import 'package:canton_tree/views/title_screen.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('Top Page Widget is displayed', (WidgetTester tester) async {
    await tester.pumpWidget(TitleScreen());
    expect(find.byType(TextButton), findsNWidgets(6));
  });
}

ウィジェットテストを実行すると、以下のようなエラーが表示されます。

No MediaQuery widget ancestor found.
TopPage widgets require a MediaQuery widget ancestor.
The specific widget that could not find a MediaQuery ancestor was:
  TitleScreen
The ownership chain for the affected widget is: "TitleScreen ← [root]"
No MediaQuery ancestor could be found starting from the context that was passed to MediaQuery.of().
This can happen because you have not added a WidgetsApp, CupertinoApp, or MaterialApp widget (those
widgets introduce a MediaQuery), or it can happen if the context you use comes from a widget above
those widgets.

解決策

MediaQueryウィジェットを使うことが前提となっているウィジェットをテストする場合は、以下のように該当ウィジェットをMaterialAppウィジェットなどで囲う必要があります。

void main() {
  testWidgets('Title Screen is displayed', (WidgetTester tester) async {
    await tester.pumpWidget(
      MaterialApp(
        home: TopPage(),
      ),
    );
    expect(find.byType(TextButton), findsNWidgets(6));
  });
}

しかし、routeを使っていたり、providerやlocalizationなどを使用している場合は、Mockや設定をする必要があります。

Mockを使うために以下のようにmockitoパッケージを追加します。

dev_dependencies:
  flutter_test:
    sdk: flutter
  test: 
  mockito: 

routeを使って、ウィジェットを表示させる場合は、こちらで説明されているように、NavigationObserverのMockを作成することでテスト可能になります。

class MockNavigatorObserver extends Mock implements NavigatorObserver {}

void main() {
  testWidgets('Title Screen is displayed', (WidgetTester tester) async {
    final mockObserver = MockNavigatorObserver();
    await tester.pumpWidget(
      MaterialApp(
        home: TopPage(),
        navigatorObservers: [mockObserver],
      ),
    );
    await tester.pumpAndSettle();
    expect(find.byType(TextButton), findsNWidgets(6));
  });
}

Providerが使われている場合は、必要なProviderでMaterialAppを括る必要がありますが、以上でウィジェットのテストが実行できるようになりました。

参考サイト

https://flutter.dev/docs/cookbook/testing/unit/introduction

https://pub.dev/packages/test

https://flutter.dev/docs/cookbook/testing/widget/introduction

https://stackoverflow.com/questions/63771432/how-to-resolve-all-the-sdk-and-dependencies-issues-after-cloning-a-project-that

https://stackoverflow.com/questions/50704647/how-to-test-navigation-via-navigator-in-flutter

https://qiita.com/chooyan_eng/items/6ffd5b07de07edafd304

関連記事

Flutterの記事一覧を見る

Flutterの質問

soichiro1210 が1年前に投稿

質問日時 2023年07月31日

a-sato が3年前に投稿

質問日時 2021年07月01日

a-sato が3年前に投稿

質問日時 2021年06月30日

takumi が3年前に投稿

質問日時 2021年05月20日

a-sato が3年前に投稿

質問日時 2021年05月14日

Flutterの質問一覧を見る
search