iOS Android

Flutterでテストコードを書こう! 単体テスト・Widgetテスト・インテグレーションテスト

投稿日:2020年3月18日 更新日:

はじめに

Flutterでは、テストコードを実装しやすい環境が整っています。この記事では、単体テスト・Widgetテスト・インテグレーションの実装方法を紹介します。

単体テスト

Dartの testパッケージを利用したテスト方法を紹介します。

testパッケージの利用

pubspec.yamltestを読み込むようにします。

testは、使用中のFlutter SDKに含まれる、 flutter_testが依存しているため、 testの最新バージョンを使用してしまうと、Packages getに失敗してしまうことがあります。
その問題を解決するため、バージョン指定には anyを使用しています。
ただし、実際には、バージョンを指定すべきだと思うため、 anyでPackages getが成功したら、 pubspec.lockで実際にインストールされたバージョンを確認し、 pubspec.yamlに反映させるべきだと思います。

テストの書き方

まずは、このような簡単なクラスをテストしてみます。

テストコードは、 test/配下にDartファイルを作成し、実装します。

テストケースごとに、 test()関数を呼び出します。第一引数はテスト名、第二引数がテストの内容となります。

テスト結果の検証は expect()関数を使用します。第一引数は検証対象、第二引数は期待値となります。もし、期待値と異なれば、テストは失敗となります。

テストの実行

テストを実行するには、作成したテストコードのDartファイルを右クリックし、 Run tests in プロジェクト名を選択して実行できます。
test()単位でテストするには、テストコードの行番号の左側にあるRunボタンをクリックすると、そのテストのみが実行されます。
コマンドで実行するには次のようにします。

モック化

例えば、テストコードを書こうとしたとき、テスト対象クラスが、Webサービスにアクセスするクラスに依存している場合、テストは自動化されても、実行環境を整える手間がかかります。
そこで、そのようなクラスはモック化(模倣)し、テストに必要なデータを返却するようにすることで、本来テストしたい領域のみを単体でテストすることができます。

mockitoの導入

pubspec.ymlに以下を追加し、Packages getします。

バージョンは、mockitoのページで最新版を確認してください。

メソッドのモック化

例として、非同期メソッドをモック化してみます。実際には、通信処理や、重い処理の実行をモック化する際に、使用できます。
こちらのサンプルコードをモック化します。

次に、モック化したテストコードです。

まず、(1)のところでモック用のクラスを宣言します。 Mockクラスを継承し、モック化したいクラスをインターフェースとして設定します。

ちなみに、Javaではここで IGreetingと命名されるようなインターフェイスを定義しておき、 GreetingクラスとMockGreetingの両方に実装させることになると思います。
しかし、Dartではモック化したいクラスをそのままインターフェイスとすることができます。
なぜなら、Dartでは暗黙的インターフェイスという仕様があり、全てのクラスはインターフェイスとして利用できるためです。
その場合、クラス内の全てのメソッドやプロパティが実装必須となります。(privateなものは除きます。)

次に、モックの実装です。
(2)の部分でモックをインスタンス化し、(3)以降のところでモックを実装していきます。
when()メソッドでモック対象を指定し、thenAnswer()メソッドでメソッドの内容を書き換え、返り値を設定します。
今回は、Future<String>が戻り値なので、Future.value()で値を返却しています。

その他のモック化

thenAnswer()以外の、モック化の方法を紹介します。
単純に返り値だけを変更したいのであれば、thenReturn()メソッドが使用できます。ただし、Futureクラスのモック化には使用できないので注意してください。

Widgetテスト

Flutterは、Widget単位でのテストもサポートしています。Widgetの状態遷移をテストコードで実装し、結果を検証することで、テストすることができます。

flutter_testの導入

flutter_testはプロジェクト作成時から入っていますが、入っていない場合はpubspec.yamlに以下を追加します。

テストの書き方

「単体テスト」で使用したGreetingクラスを使用して、Widgetを実装します。

名前を入力して、「あいさつする」ボタンをタップすると、テキストが更新されるシンプルなWidgetです。
このWidgetのテストコードのサンプルです。

テストコードの中身を見ていきましょう。

Widgetの取得方法

Widgetを取得する代表的な方法を紹介します。

find.text()メソッド

Textや、Textを内包しているWidget(ボタンなど)を取得することができます。

find.byKey()メソッド

取得したいWidgetに設定した Keyで、Widgetを特定します。

Widgetの操作方法

findで取得したWidgetを操作する代表的な方法を紹介します。

tap()メソッド

引数に渡されたボタンをタップします。

enterText()メソッド

第1引数で渡されたWidgetに、第2引数のテキストを入力します。

画面が変化した後に呼ぶpump()メソッド

ボタンアクション等によってWidgetツリーを更新した直後にexpect()メソッドで検証する場合、ツリーが更新されるまで待つ必要があります。
そのような時は、pump()メソッドを挟む事で、処理待ちを行うことができます。

検証

単体テストの時と同じようにexpect()メソッドを使用します。

第1引数に検証したいWidget、第2引数に取得したWidgetを検証する方法を指定します。検証方法は次の4つです。

  • findsOneWidget
    1つのWidgetが見つかること
  • findsNothing
    Widgetが見つからないこと
  • findsWidgets
    1つ以上のWidgetが見つかること
  • findsNWidgets
    特定の数のWidgetが見つかること

テストの実行

単体テストと同じ方法で実行できます。
コマンドで実行するには次のようにします。

インテグレーションテスト

インテグレーションテストでは実機でアプリを実際に動作させ、自動的に操作・検証することで、アプリ全体を網羅的にテストします。
単体テストより実行に時間はかかりますが、実機で通しテストを行う点がポイントです。
「Widgetテスト」で使用したページを使用して、インテグレーションテストを行なっていきます。

flutter_driverの導入

pubspec.yamlに以下を追加します。

testパッケージに依存しているため、testパッケージも使用できるようにします。

テストの書き方

単体テストやWidgetテストとは異なり、インテグレーションテストはアプリとは異なるプロセスで実行されます。そのため、 test_driverディレクトリを作成し、配下に app.dartapp_test.dartを作成します。
ファイル構成は以下のようになります。

app.dartの実装

app.dartは、FlutterDriverを有効化し、アプリをドライブする実装をします。

app_test.dartの実装

app_test.dartには、テストスイートを実装します。

GreetingPageのテストと、カウンター画面(MyHomePage)への
テストコードの中身を見ていきましょう。

Widgetの取得方法

Widgetは以下のように取得します。

引数で渡す値は Widget build()key: const Key('name text field')と指定した値を渡します。

Widgetの操作方法

findで取得したWidgetを操作する代表的な方法を紹介します。

tap()メソッド

引数に渡されたボタンをタップします。

enterText()メソッド

現在フォーカスが当たっているTextFieldにテキストを入力します。(既存のテキストは削除されます。)
WidgetTestの時とは異なり、あらかじめTextFieldをタップしてフォーカスを当てておく必要があるため、tap()メソッドとセットで使うケースがほとんどだと思います。

画面表示結果の検証

expect()で検証します。

第1引数でdriver.getText()メソッドを呼び出し、Widgetのテキストを取得します。第2引数に渡した文字列と合致しているかどうか、検証されます。

テストの実行方法

実機もしくはエミュレータ を起動している状態で、以下コマンドを実行すると、テストが実行されます。

テストが成功すると、以下のように出力されます。

さいごに

Flutterでは単体からインテグレーションテストまで、幅広くテストを自動化できます。手軽に実装できるので、どんどん実戦投入していきたいものですね。

おすすめ書籍

基礎から学ぶ Flutter Flutter モバイルアプリ開発バイブル プログラミング言語Dart

blog-page_footer_336




blog-page_footer_336




-iOS, Android
-, , ,

執筆者:


comment

メールアドレスが公開されることはありません。

CAPTCHA


関連記事

[Kotlin]DatePickerDialogとTimePickerDialogを使って見た。

1 はじめに2 Anko Commons3 DatePickerDialog3.1 DatePickerFlagment3.2 呼び出し方4 TimePickerDialog4.1 TimePicke ...

UIWebViewからWKWebViewへの移行

1 はじめに2 ターゲットとなるUIWebViewで行なっていること3 URLへのアクセス4 ローカルHTMLの読み込み5 ページを戻す、進める6 ページの読み込み開始時や終了時に処理を行う(dele ...

【Kotlin】FirebaseAuthenticationでGoogle・Facebook連携する

1 はじめに2 Firebaseプロジェクトの設定3 build.gradleに追記4 Googleログイン5 Facebookログイン6 さいごに7 参考8 おすすめ書籍 はじめに はじめまして。m ...

swift

iOSアプリのチュートリアルに便利なMMPopLabel

1 はじめに2 準備3 実装3.1 Storyboard3.2 MMPopLabelの準備3.3 MMPopLabelの表示3.4 Delegate4 さいごに はじめに こんにちは、nukkyです。 ...

swift

Swift3でMapKitの吹き出し(Callout)タップを取得したい!

1 はじめに2 MapKitでの吹き出しタップ3 吹き出しのみタップしたい!4 さいごに はじめに こんにちは、nukkyです。 今回、iOSのMapKitでGoogleMapのように 吹き出しのタッ ...

フォロー

follow us in feedly

blog-page_side_responsive

2020年3月
1234567
891011121314
15161718192021
22232425262728
293031 

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。