こんにちは。
人間ミスはつきものですね。
ミスを見つけるためにも、ある程度の規模や複雑性のあるコードを書いた場合、ユニットテストを書いたほうがいいと思っています。(実践できているかはさておき)。
今回、日付周りの処理を実装したのですが、この辺パターンが膨大になるのでテストを書きました。
その備忘録です。
この記事で説明すること
- 既存機能(DateTime)を拡張する方法
- dartのユニットテストの基本的な方法
- ユニットテストで日付モックを使う方法(pluginなし)
既存機能(DateTime)を拡張する方法
他の言語にもありますが、dartにも既存機能を拡張する方法があります。
個人的には下記のことに気をつけています。
- 不用意に拡張しない
- 拡張したことがわかるように〇〇_estensionsという名前にしている
datetime_extensions.dart
extension DateTimeExtension on DateTime {
// インスタンスメソッドの拡張
// thisで自分自身(dateTimeインスタンス)にアクセス
String get ymdJp => DateFormat("yyyy年M月d日", "ja_JP").format(this);
// クラス変数
static DateTime _customTime;
static set customTime(DateTime customTime) {
_customTime = customTime;
}
// クラスメソッドとして拡張
static DateTime get current {
return _customTime ?? DateTime.now();
}
}
解説
-
extension Extension名 on もとのクラス名
でクラスを拡張する - extensionの中に、拡張したい機能を追加する(インスタンスメソッド、クラスメソッドのどちらも拡張可能)
拡張したコードの呼び出し方法
こんな感じで呼び出せます。インスタンスメソッドはわかりやすいですね。
クラスメソッドは、クラスが変わっているので注意が必要です。
あと、extensionしたファイルをimportする必要があります。
sample_widget.dart
// importの場所は人によって異なるので注意してください
import 'package:cojicaji/extension/datetime_extension.dart';
import 'package:flutter/material.dart';
class SampleWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
DateTime dateTime = DateTime.now();
return Text(dateTime.ymdJp);
}
}
review_logic.dart
import 'package:cojicaji/extension/datetime_extension.dart';
class ReviewLogic {
/// レビュー依頼を表示するかどうかを判定するダミーロジック
bool isShowReview() {
// 前回のレビュー発火から28日以上立っているか?(標準ライブラリでNヶ月計算しにくいので日付換算)
// Yes -> レビューだす / No -> レビュー依頼ださない
// 本日の日付と最終レビュー依頼日付を取得する。最終レビュー日付依頼のコードはダミー
DateTime today = DateTimeExtension.current;
DateTime lastReviewRequestDate = getLastReviewRequestDateTime();
Duration difference = today.difference(lastReviewRequest);
if (difference.inDays < 28) {
return false; // noNeedReview;
}
return true;
}
}
日付モックをUnitTestする方法
サンプルコードとざっくり解説します。
-
void main() {}
の中にテストを書く -
group
を使ってテストコードをグルーピングできる。ネスト可能。 -
setUp()
は、test()
の前に毎回走る処理。共通する初期化などを書く - テストは無形関数を使って、
test('testケース', () {})
のように書く。日本語OK。 -
expect
を使って、結果を評価する
hoge_test.dart
import 'package:cojicaji/extension/datetime_extension.dart';
void main() {
group('レビュー依頼の判定', () {
group('28日以上経過してる場合', () {
setUp(() {
// テストが1つしかないなら、ここに書く必要は本当はないが、解説の都合で記載。
// 日付のモック更新
var currentUtcDateTimeMock = DateTime.utc(2021, 1, 28);
DateTimeExtension.customTime = currentUtcDateTimeMock;
});
test('レビュー依頼がでること', () {
var logic = new ReviewLogic();
var result = logic.isShowReview();
expect(result, true);
});