🕰️

Flutterの自動テスト Step2 〜Unit Test DateTime.now()に依存する場合〜

2023/11/22に公開

Flutter 自動テスト シリーズについて

Flutterの自動テストをStep by Stepで説明しています。

一連の記事を「本」(無料)にまとめました。
https://zenn.dev/yu1ro/books/2b5f8d32cc2668

今回の対象

今回もUnit Testですが、関数内でDateTime.now()を使っている場合です。

例えばこんなコードがあります。
直前の日曜日のDateTimeを取得する仕様です。

latest_sunday.dart
DateTime getLatestSunday() {
  final today = DateTime.now();
  if (today.weekday == DateTime.sunday) {
    return DateTime(today.year, today.month, today.day);
  }

  return DateTime(today.year, today.month, today.day - today.weekday);
}

課題: 実行時間によって結果が変わってしまう

このコードをテストしようとすると DateTime.now() が実行時間によって動作が変わるってしまいます。

latest_sunday_test.dart
void main() {
  test('直前の日曜日は2023-11-05', () {
    final latestSunday = getLatestSunday();
    expect(latestSunday, DateTime(2023, 11, 5));
  });
}

参考にカレンダーを貼っておきます。

このテストは実行時間が2023年11月05日〜2023年11月11日の間なら成功しますが、
それ以外の日に失敗してしまいます。

「今」を固定する

DateTime.now()で取得する日時をテスト実行中に固定することで解決します。

必要なライブラリをインストール

まずはclockとfakeAsyncをインストール

flutter pub add clock
flutter pub add fake_async --dev

DateTime.now()をclock.now()に置き換える

テスト対象のコードを書き換えます。

latest_sunday.dart
import 'package:clock/clock.dart';

DateTime getLatestSunday() {
  final today = clock.now();
  if (today.weekday == DateTime.sunday) {
    return DateTime(today.year, today.month, today.day);
  }

  return DateTime(today.year, today.month, today.day - today.weekday);
}

テストコードでnowを固定する

latest_sunday_test.dart
void main() {
  test('2023-11-8の直前の日曜日は2023-11-05', () {
    fakeAsync(initialTime: DateTime(2023, 11, 8), (_) {
      expect(getLatestSunday(), DateTime(2023, 11, 5));
    });
  });
}

このように書くことで、「今」が2023年11月8日の時のテストができるようになりました。
あとは前提条件のinitialTimeと期待値を色々試すコードを書けば完了です。

動作するコードはこちら

https://github.com/yu1ro/step_by_step_test

次の記事はこちら

https://zenn.dev/yu1ro/articles/ebcae8f2181030

最後に(宣伝)

友人と個人開発でゲーミフィケーション記録アプリ「HibaQuest」を作っています。
よければお試しください。
https://hiba.quest

Discussion