【Flutter/Dart】 testについて
概要
昨今、品質の担保や向上が注目される中でシステムの各分野においてもテストの自動化が注目さている。
今まではテスト仕様書を作成し、それっを目視でテストするそんなものもあったは、回数を重ねれば同じテストをしても精度が低い場面に直面することもあるだろう。
なので最近はテストはコーディングするのが主流になっている。
test
- 動画
- 方法について
主には以下の3種類がある。
- Integration
- Unit
- Widget
やってみた。
共通部分
- test用のライブラリの取り込み
多分、書いてあるが、 以下を記述してflutter pub get
を叩く
dev_dependencies:
integration_test:
sdk: flutter
flutter_test:
sdk: flutter
- test用のフォルダとdartファイルを準備する。
your_app/
lib/
main.dart
integration_test/
app_test.dart
test/
unit/
unit_test.dart
widget/
widget_test.dart
Integrationテストの場合
import 'package:flutter_test/flutter_test.dart'; //testコードはこれをimport
import 'package:integration_test/integration_test.dart'; //インテグレーションtestコードはこれをimport
import 'package:introduction/main.dart' as app; // as appでrunAppを記述したdartファイルを呼び出す。
void main() {
// インテグレーションテストの場合はこれを1行目に書く
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// テストをグループ化するコード
group('end-to-end test', () {
// Widgetテストのコード
testWidgets('tap on the floating action button, verify counter',
(WidgetTester tester) async {
// ここでrunAppを起動
app.main();
// pumpAndSettleで画面を起動を待つ
await tester.pumpAndSettle();
// 初期値を確認
expect(find.text('0'), findsOneWidget);
// Widgetをtooltipをキーに見つける。…①
final Finder fab = find.byTooltip('Increment');
// ①で見つけたWidgetをタップするコード…②
await tester.tap(fab);
// ②でタップした結果を待つ、ロジック
await tester.pumpAndSettle();
// ボタン押下で内容が変化したかを確認するロジック
expect(find.text('1'), findsOneWidget);
});
});
}
【解説】
-
Finder
Widgetをみつけて、そのWidgetに対してアクションを起こしたり、Widgetが格納している情報を取り出す。 -
expect
expect(A, B)
のA:Finderで指定した情報をとりだす。
、B:取り出した情報にマッチするじょうけんがいくつ存在しているかを指定する。
findsOneWidget // Finderで指定した条件のWidgetが一つだけ存在している場合。 findsNothing // Finderで指定した条件のWidgetが存在していない。 findsWidgets // Finderで指定した条件のWidgetが複数存在している場合。 findsNWidgets(n) // Finderで指定した条件のWidgetがn個存在している場合。
unitテストの場合
import 'package:flutter_test/flutter_test.dart';
void main() {
test('unit Test', () {
var test = 5;
expect(test, 5);
});
}
まぁ、integrationテストでほとんど触れているので特に何もいうことはないが、
controller,service,providerなどのテストで使用できる。
widgetテストの場合
import 'package:flutter_test/flutter_test.dart';
testWidgets('NoteTest', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
onGenerateRoute: (settings) {
if (settings.name == '/') {
return MaterialPageRoute(builder: (_) => const NoteListPage());
} else if (settings.name == '/edit') {
final arguments = settings.arguments as String?;
return MaterialPageRoute(
builder: (_) => NoteEditPage(note: arguments ?? ""),
);
}
throw Exception('Route not found');
},
),
);
expect(find.text('There\'s nothing to show'), findsOneWidget);
await tester.tap(find.byKey(const Key('add_note')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('edit_text')), findsOneWidget);
await tester.enterText(find.byKey(const Key('edit_text')), 'ゴゴゴゴゴ・・・。');
await tester.tap(find.byKey(const Key('commit_button')));
await tester.pumpAndSettle();
expect(find.text('ゴゴゴゴゴ・・・。'), findsOneWidget);
・・・
});
Widgetをガチの単体テストでやりたい場合は、tester.pumpWidget
でMaterialApp
を包んで中にテストしたいWidgetを入れます。あとはインテグレーションテストと同じ方法でいけます。
非同期のテストに関して
ライブラリを追加します
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.0
mockito: #これと
build_runner: #これを追加する。
ライブラリ | 内容 |
---|---|
mockito | mockitoで非同期実行用クラスを自動生成します。 |
build_runner | mockitoをビルドするために必要です。 |
サンプルコード
- まずはこの状態でビルドします
([テストしたいClass])
void main() {
}
- 上記、コードを作成し、ワークディレクトリで以下のコマンドを叩きます。
$ flutter pub pub run build_runner build
すると、MockテストしたいClass
というクラスができます。
- これを使ってテストコードを書きます。
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:sample/apis/MockビルドしたいClass.dart';
import 'package:sample/models/return_mock.dart';
import 'api_test.mocks.dart';
([テストしたいClass])
void main() {
var repository = MockテストしたいClass();
test('Testing cat sound method.', () async {
final returnMock = ReturnMock(
description: '',
);
when(repository.search('****')).thenAnswer((_) async => returnMock);
expect(await repository.search('****'), returnMock);
verify(repository.search('****'));
});
}
こんな感じでMockitoを使うことで非同期処理のテストコードを記述することも可能です。
Finderについて
これは、Widgetを見つけるためのファンクションだが、見つける手段が山のようにあるので以下で参照してほしい。主に使うのはbyKey(const Key('キーの名前'))
である
Keyについて
Keyはテストにおいては、Widgetを見つけるためにWidgetに設定することができるKey値である。
だいたいどのWidgetにも設定できる。
Text(
'Test',
key: const ValueKey('sample_key'),
),
Keyの種類
- GlobalKey
- GlobalKey
- LocalKey
- UniqueKey
- ValueKey
- ObjectKey
- PageStorageKey
詳しくは動画見てチェック
最後に
今回は長くなったのでこの辺にしておくがもっともっとTestは奥が深いので、実装をもっとして深めていければと思う。
Discussion