👏

【Flutter】ユニットテストで使用するメソッド集

に公開

はじめに

Flutter でユニットテストを書く際には、様々なテストメソッドやアサーションメソッドが用意されています。これらのメソッドを適切に使いこなすことで、より効果的なテストを書くことができます。この記事では、ユニットテストで使用するメソッドをメモとして記しておきます。

サンプルコード

https://github.com/muranakar/flutter_unit_test

基本的なテスト構造メソッド

まずは、テストの基本構造を作るために使用するメソッドを見ていきましょう。

testメソッド

testメソッドは最も基本的なテスト単位を定義します。

// 基本的なテストの書き方
test('テストケースの説明', () {
  // テストの内容
});

groupメソッド

groupメソッドは関連するテストをグループ化します。

group('テストグループの説明', () {
  // 複数のテストケース
  test('テストケース1', () {
    // テスト内容1
  });

  test('テストケース2', () {
    // テスト内容2
  });
});

setUptearDownメソッド

setUpはグループ内の各テスト前に実行される共通の準備処理、tearDownは各テスト後のクリーンアップ処理を定義します。

group('テストグループ', () {
  // テストの前に実行される
  setUp(() {
    // 共通の準備処理
  });

  // テストの後に実行される
  tearDown(() {
    // 共通のクリーンアップ処理
  });

  test('テストケース', () {
    // テスト内容
  });
});

setUpAlltearDownAllメソッド

setUpAllはグループ内の全テスト実行前に一度だけ実行され、tearDownAllは全テスト完了後に一度だけ実行されます。

group('テストグループ', () {
  // グループ内の全テスト実行前に一度だけ実行
  setUpAll(() {
    // 初期化処理(データベース接続など)
  });

  // グループ内の全テスト完了後に一度だけ実行
  tearDownAll(() {
    // 終了処理(データベース切断など)
  });

  // テストケース
});

基本的なアサーションメソッド

テスト結果を検証するためのアサーションメソッドを見ていきましょう。

expectメソッド

expectは実際の値と期待する値を比較する最も基本的なアサーションです。

test('基本的な比較', () {
  final actual = 1 + 1;
  expect(actual, 2); // actualが2であることを検証
});

equalsマッチャー

equalsは値の等価性を検証します(デフォルトで使用されるため、通常は省略可能)。

expect(actual, equals(2)); // expect(actual, 2)と同じ

isTrueisFalseマッチャー

ブール値の検証に使用します。

test('ブール値のテスト', () {
  expect(2 > 1, isTrue);
  expect(2 < 1, isFalse);
});

isNullisNotNullマッチャー

null かどうかを検証します。

test('nullチェック', () {
  var value;
  expect(value, isNull);

  value = 'not null';
  expect(value, isNotNull);
});

コレクション関連のマッチャー

リストや配列などのコレクションを検証するためのマッチャーです。

containsマッチャー

コレクションに特定の要素が含まれているかをチェックします。

test('コレクションに要素が含まれているか', () {
  final list = [1, 2, 3];
  expect(list, contains(2));
});

containsAllマッチャー

コレクションに複数の要素がすべて含まれているかをチェックします。

test('コレクションに複数要素が含まれているか', () {
  final list = [1, 2, 3, 4];
  expect(list, containsAll([2, 4]));
});

hasLengthマッチャー

コレクションの長さを検証します。

test('コレクションの長さ', () {
  final list = [1, 2, 3];
  expect(list, hasLength(3));
});

isEmptyisNotEmptyマッチャー

コレクションが空かどうかを検証します。

test('コレクションの空チェック', () {
  expect([], isEmpty);
  expect([1, 2], isNotEmpty);
});

文字列関連のマッチャー

文字列を検証するためのマッチャーです。

startsWithendsWithマッチャー

文字列の先頭や末尾を検証します。

test('文字列の先頭と末尾', () {
  final str = 'Hello, World!';
  expect(str, startsWith('Hello'));
  expect(str, endsWith('World!'));
});

containsマッチャー(文字列版)

文字列に特定の部分文字列が含まれているかをチェックします。

test('文字列に部分文字列が含まれているか', () {
  final str = 'Hello, World!';
  expect(str, contains(', '));
});

matchesマッチャー

正規表現パターンにマッチするかをチェックします。

test('正規表現のマッチ', () {
  final email = 'test@example.com';
  expect(email, matches(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'));
});

数値関連のマッチャー

数値を検証するためのマッチャーです。

greaterThanlessThanマッチャー

大小関係を検証します。

test('数値の大小関係', () {
  expect(5, greaterThan(3));
  expect(3, lessThan(5));
});

greaterThanOrEqualTolessThanOrEqualToマッチャー

以上・以下の関係を検証します。

test('数値の以上・以下関係', () {
  expect(5, greaterThanOrEqualTo(5));
  expect(3, lessThanOrEqualTo(3));
});

inClosedOpenRangeマッチャー

指定した範囲内にあるかをチェックします。

test('数値の範囲チェック', () {
  // 1 <= value < 5 の範囲
  expect(3, inClosedOpenRange(1, 5));
});

例外のテスト

例外が正しく発生するかをテストするためのメソッドです。

throwsAマッチャー

特定の例外が発生することを検証します。

test('例外のテスト', () {
  expect(() => throw Exception('Error'), throwsA(isA<Exception>()));
});

この例では、関数が Exception 型の例外をスローすることを検証しています。

特定の例外クラスのテスト

特定の例外クラスが発生することを検証します。

test('特定の例外クラスのテスト', () {
  expect(() => throw FormatException(), throwsFormatException);
  expect(() => throw ArgumentError(), throwsArgumentError);
});

様々な種類のエラーマッチャーが用意されています。

マッチャー名 確認するエラー 用途
throwsArgumentError ArgumentError 引数の問題をチェック
throwsRangeError RangeError 範囲外のアクセスをチェック
throwsStateError StateError 不正な状態をチェック
throwsException Exception 一般的な例外をチェック
throwsFormatException FormatException フォーマットエラーをチェック
throwsNoSuchMethodError NoSuchMethodError 存在しないメソッド呼び出しをチェック
throwsUnsupportedError UnsupportedError サポートされていない操作をチェック

非同期テスト

非同期処理をテストするためのメソッドです。

async/awaitを使用したテスト

非同期処理を普通にテストする場合は、テスト関数をasyncにしてawaitを使用します。

test('非同期テスト', () async {
  // 非同期処理を行う関数
  Future<int> fetchNumber() async {
    await Future.delayed(Duration(milliseconds: 100));
    return 42;
  }

  final result = await fetchNumber();
  expect(result, 42);
});

expectLaterメソッド

将来の値(Future)に対する検証を行います。

test('Futureの検証', () async {
  Future<int> fetchNumber() async {
    await Future.delayed(Duration(milliseconds: 100));
    return 42;
  }

  await expectLater(fetchNumber(), completion(equals(42)));
});

completionマッチャー

Future が完了したときの値を検証します。

test('Futureの完了値', () {
  Future<String> fetchString() async {
    await Future.delayed(Duration(milliseconds: 100));
    return 'Hello';
  }

  expect(fetchString(), completion('Hello'));
});

emitsマッチャー

ストリームから発行される値を検証します。

test('ストリームのテスト', () {
  final controller = StreamController<int>();

  // 値を発行
  controller.add(1);
  controller.add(2);
  controller.close();

  expect(controller.stream, emitsInOrder([1, 2, emitsDone]));
});

emits 関連であれば、以下のマッチャーが用意されています。

emits - ストリームが特定のイベントを発行するかテスト
emitsDone - ストリームが「完了」イベントを発行するかテスト
emitsError - ストリームがエラーイベントを発行するかテスト
emitsInOrder - 複数のイベントが特定の順序で発行されるかテスト

まとめ

Flutter のユニットテストでは、様々なメソッドとマッチャーを組み合わせることで、効果的なテストを書くことができます。

基本的なテスト構造(testgroupsetUpなど)と、様々な検証メソッド(expectとそれに関連するマッチャー)を適切に組み合わせることで、様々なシナリオのテストが可能になります。

サンプルコード

https://github.com/muranakar/flutter_unit_test

Discussion