Flutter(Dart)のテスト手法についてまとめてみた

Flutter(Dart)のテストの種類

UnitTest

メソッド単位でのテスト。

例)入力した値を2倍にして出力する関数について、「1を入力したら2が出力されるだろう」「5を入力したら10が出力されるだろう」

WidgetTest

Widget単位でのテスト。

ある操作に対して画面の変化を確認するイメージ。

例)画面上の〇ボタンをタップしたらテキストの値が〇〇に変化するだろう。
画面上の△ボタンをタップしたらテキストの値は△△に変化するだろう。

GoldenTest

画面のスクリーンショットを用いてテストを行う手法。

UnitTestのやり方

まずは、テスト対象のメソッドを用意します。

今回は例として「入力値を2倍して出力するメソッド」を用いてUnitTestを行います。

class NumericUtils {
  int doubleValue(int value) => value * 2;
}

テスト対象のメソッドが用意できたら次は、テスト用のクラスとメソッドを用意します。

プロジェクトファイル直下にtestフォルダがあると思いますので、その中に、クラスを作成します。

名前はなんでもいいですが、”テスト対象のメソッドが存在するクラスのクラス名_test”と付けるのが一般的かと思います。

import 'package:flutter_test/flutter_test.dart';
import 'package:hoge_hoge/utils/numeric_utils.dart';

void main() {
  NumericUtils target = NumericUtils();
  setUp(() async{
    target = NumericUtils();
  });

  test('doubleValue', () async {
    //テストケース①・・・入力値=1とした場合に出力値=2となるだろう
    expect(target.doubleValue(1), 2);
    //テストケース②・・・入力値=5とした場合に出力値=10となるだろう
    expect(target.doubleValue(5), 10);
    //テストケース③・・・入力値=0とした場合に出力値=0となるだろう
    expect(target.doubleValue(0), 0);
  });
}

UnitTest及び後程説明を行うWidgetTestについてはflutter_testパッケージを使用します。

上記パッケージについては、プロジェクトを作成した際に、pubspec.yamlにデフォルトでインストールされています。

もし、インストールされていない場合は、下記コードをpubspec.yamlに追記してpub getコマンドを実行してみてください。

dev_dependencies:
  flutter_test:
    sdk: flutter

UnitTestを行う際は、「◯◯を入力すると△△が出力されるだろう」と予想を立てておくことが重要だと考えます。

それが1つのテストケースにもなりますしね…

テスト用のメソッドが作成できたら、実行することでテストを行うことができます。

テストが成功するとコンソールに成功の目印が表示されます。

失敗するとコンソールに実際に出力された値が表示されます。

失敗のパターンも載せておきます。

import 'package:flutter_test/flutter_test.dart';
import 'package:hoge_hoge/utils/numeric_utils.dart';

void main() {

  NumericUtils target = NumericUtils();
  setUp(() async{
    target = NumericUtils();
  });

  test('doubleValue', () async {
   //テストケース④・・・入力値=-3とした場合に出力値=6となるだろう
    expect(target.doubleValue(-3), 6);
  });
}

この場合は、 「-3×2=6となるだろう」というテストケースを用意します。

しかし、実際には「-6」が正解なのでテストが失敗します。

Expected: <6>
  Actual: <-6>

Expectedには自分が出力値として予想していた値Actualには実際にメソッドを通した結果の値が表示されます。

ですので、今回の例はテストケースに誤りがあったということになります。

テストに失敗した際は、自分の作成したテストケースに誤りがあるのか、また、作成したメソッドに誤りがあるのかをはっきりさせることが重要だと考えます。

WidgetTestのやり方

プロジェクト作成時のデフォルトのカウンターアプリを例としてテストをしていきます。

Flutterに触れたことがある人は馴染みがありますよね。

その画面でWidgetTestを行います。

次に、テストコードを確認していきましょう。

こちらもプロジェクト作成時に自動的にtestフォルダに作成されるテストクラスとなっています。

void main() {
  testWidgets('Counter increments smoke test', (WidgetTester tester) async {

    // アプリを指定
    await tester.pumpWidget(const MyApp());

    // 初期表示の時点では、
   // ’0’のテキストは1つ、’1’のテキストは存在しないだろうという内容のテスト
    expect(find.text('0'), findsOneWidget);
    expect(find.text('1'), findsNothing);

    // +ボタンをタップする
    await tester.tap(find.byIcon(Icons.add));
   // ボタンタップ後の内容を画面に反映
    await tester.pump();

    // ボタンをタップした結果、
    // ‘0’のテキストは存在しない、’1’のテキストは1つ存在するという内容のテスト
    expect(find.text('0'), findsNothing);
    expect(find.text('1'), findsOneWidget);
  });
}

WidgetTestは上記でも述べたように画面の状態をテストする手法となります。

初期表示の時点では画面上の数値カウント用のテキストの内容は0となっているため、9行目、10行目のテストを行なって画面の状態が正しいことを確認します。

さらに、+ボタンタップの操作をコードで実行できるので、ボタンタップ後の状態が正しいかどうかということも確認することができます。

UnitTestについてはJUnitやNUnitを触っていたことがあったのですぐ理解できました。
WidgetTestは全く馴染みがなかったので理解できるか不安でしたが、とてもシンプルにテストコードを書くことができるのですぐ理解できました。

今回説明を行わなかったGoldenTestについては学習中のため、後日改めて説明させていただきます。