Share
Embed
Transcript
22 slides
-
自己紹介 とっく(@tokkuu) • 都内AdTech企業のWebエンジニア • php/python/TypeScript • AWS周り 3-tierからサーバレスまで •
元々はSIerのインフラエンジニア • Flutter歴は1年半くらい 3 -
はじめに • 説明すること ◦ Riverpodでのユニットテストの書き方 ◦ RiverpodでのWidgetテストの書き方 • 説明しないこと ◦
DIを用いたProviderでのテストの書き方 ◦ Integration Testについて ◦ CIへの組み込みやDDDについて • Providerでのテストについて ◦ Flutterで単体テストを行う方法とGitHub Actionsを使った自動化 • DDDの説明(同じサンプルを使用) ◦ hooks_riverpod + state_notifier + freezedでのドメイン駆動設計 4 -
Flutterにおけるテストの種類 Flutterには3種類のテストがある 公式ページ:https://flutter.dev/docs/cookbook/testing ・Unit Test ・Widget Test ・Integration Test いわゆる単体テスト。関数、メソッド、クラスの検証を行う
Widgetが正しく生成されるかのテスト。 結合テスト。シナリオを書いてエミュレータ上で自動操作によるテス トが行える。 6 -
Unitテストの書き方と実行方法 プロジェクトルートの testフォルダの下に XXX_test.dartファイルを作成 import 'package:flutter_test/flutter_test.dart' ; import 'package:todo_app_sample_flutter/data/todo_item.dart' ;
void main() { group('TodoItemのゲッターのテスト ', () { final TodoItem todoItem = TodoItem( id: 0, title: 'title', body: 'body', createdAt: DateTime (2020, 1, 1), updatedAt: DateTime (2020, 1, 1), isDone: true, ); test('idのテスト', () { expect (todoItem.getId, 0); }); 8 -
Unitテストの書き方と実行方法 プロジェクトルートの testフォルダの下に XXX_test.dartファイルを作成 import 'package:flutter_test/flutter_test.dart' ; import 'package:todo_app_sample_flutter/data/todo_item.dart' ;
void main() { group('TodoItemのゲッターのテスト ', () { final TodoItem todoItem = TodoItem( id: 0, title: 'title', body: 'body', createdAt: DateTime (2020, 1, 1), updatedAt: DateTime (2020, 1, 1), isDone: true, ); test('idのテスト', () { expect (todoItem.getId, 0); }); main関数の中に 実際のテストを記載 test(‘テストケース名’,(){ 実際のテスト処理 expect(結果,期待する値); }); group()でテストケースを まとめることが出来る。 9 -
サンプルプロジェクトの説明 • DDDぽく書いている • application層の todo_app_service.dartがdomain層の classを使う形 • ビジネスロジックのテストという文脈で は、todo_app_service.dartを
テストすれば十分 • このプロジェクト自体の解説は Qiitaの記事参照 • 全体のコードはこちら 12 -
サンプルプロジェクトの説明 - TodoAppService • todo_app_serviceは todoListRepositoryに依存して いる • todoListRepositoryはFirebase との通信を担う
• DDDじゃない場合、MVVM + Repositoryのパターンなどで は、View Modelでテストすれば 良い 13 -
テストの準備 - TodoListRepositoryのモックを作る • TodoListRepositoryを実装した TodoListRepositoryMemを作 る • TodoListRepositoryMemでは Firebaseとの通信を行わず、テ
スト用に一時的にデータを貯め れるように実装しておく • コード 14 -
テストの準備 - ProviderContainerでoverrideする • Riverpodでは ProviderContainerを使ってモッ ク用のクラスを宣言することで、 Providerを上書きできる。 • 右のように
TodoListRepositoryMemを 宣言しておくことで このコンテナから呼び出したリ ポジトリやサービスでは 上書きされたモック用クラスが 呼び出される様になる。 15 -
Unit Test - 宣言 • Widgetの生成が絡まない ロジックをテストする • setUpやtearDownが使える ので、先程のコンテナの宣言や
データのセットが行える。 • Null Safetyなバージョンの Flutterであれば、コンテナや モックはlateで宣言しておくこと でnon-nullableに扱える 17 -
Unit Test - 実行 1. 空のTodoItemを_repositoryに セットし、自動生成され 割り当てられたnextIdを取得 2. テスト対象のクラスを
インスタンス化 3. テスト対象のメソッドを 実行し結果を expectメソッドで比較 2. 3. 1. 18 -
WidgetTest - 宣言 • モック用クラスは引き続き containerから取得 • Widgetを生成するために、 tester.pumpWidgetの中で ProviderScopeを宣言し、モック
にoverride • childの中でテスト対象Widget の描画に必要なWidget、 MaterialAppなどを宣言した上 で対象のWidgetを宣言 20 -
WidgetTest - 実行 • find.textで描画されたWidgetの 中のテキストを探す。 findsOneWidgetは「それが1つ あること」という意味になる。 • tester.tapなどで、特定のIcon
などを探してボタンをタップさせ ることもできる。 21 -
まとめ • Riverpodで記述するときは、Repositoryをあとからoverrideできるため、わざわざ 抽象クラスを作っておいて、DIできるようにドメインクラスを実装する必要がない • Unit Testのほうが比較的簡単に、最低限のロジックのテストが書きやすい • CI組んでおけば、快適にTDDできそう •
Widget Testまで書いて、Codecovなどを使ってカバレッジを可視化して、CI組んで Slack通知まで設定しておくと快適に、より安全に開発が進められると思いました。 (関連記事) ご清聴ありがとうございました