この記事は、【 可茂IT塾 Advent Calendar 2023 】の14日目の記事です。
TDD(テスト駆動開発)を行う時に、FirebaseAuth の認証系のテストについて
色々と調べたので、基本的な部分を記事にしました。誰かのお役に立てれば、幸いです。
この記事では、Flutterのテストについては詳しく説明していないので、
知りたい方は下の記事などが参考になると思われます。
この記事では、Widgetテストにおける FirebaseAuth のテストについて書いてあります。
実機やエミュレーターを使用しないWidgetテストでは、FirebaseAuth のテストは、モックを使用して行います。
モック用のパッケージが用意されており、こちらを使用します。
ちなみに、状態管理は riverpod です。
ドキュメントにもテストの項目が用意されているので、こちらも参考になります。
はじめに
今回テストするのは、signOut のメソッドだとします。下記がコード例です。
import 'package:firebase_auth/firebase_auth.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'auth.g.dart';
@Riverpod(keepAlive: true)
FirebaseAuth firebaseAuth(FirebaseAuthRef ref) => FirebaseAuth.instance;
@riverpod
UserAuth userAuth(UserAuthRef ref) {
final instance = ref.watch(firebaseAuthProvider);
return UserAuth(auth: instance);
}
class UserAuth {
UserAuth({
required FirebaseAuth auth,
}) : _auth = auth;
final FirebaseAuth _auth;
Future<void> signOut() async {
await _auth.signOut();
}
}
FirebaseAuth.instance を Provider に持たせておきます。
下記が、テストするWidgetです。
ElevatedButton(
onPressed: () async {
final userAuth = ref.watch(userAuthProvider);
await userAuth.signOut();
},
child: const Text('Sign Out!'),
),
次にテストのコードですが、FirebaseAuth のテストは、firebase_auth_mocks の Github に
コード例が書かれており、そちらがとても参考になります。
テストのコードです。
import 'package:firebase_auth_mocks/firebase_auth_mocks.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:x_test/auth/auth.dart';
import 'package:x_test/main.dart';
void main() {
late MockFirebaseAuth mockFirebaseAuth;
setUp(
() {
final tUser = MockUser(
isAnonymous: false,
email: 'bob@thebuilder.com',
displayName: 'Bob Builder',
);
mockFirebaseAuth = MockFirebaseAuth(signedIn: true, mockUser: tUser);
},
);
testWidgets('Sign Out Test', (WidgetTester tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
firebaseAuthProvider.overrideWithValue(mockFirebaseAuth),
],
child: const MaterialApp(
home: MyApp(),
),
),
);
// ログインしていることの確認
expect(mockFirebaseAuth.currentUser, isNotNull);
final signOutButtonFinder =
find.widgetWithText(ElevatedButton, 'Sign Out!');
// 描画を確認
expect(signOutButtonFinder, findsOneWidget);
// Buttonをタップ
await tester.tap(signOutButtonFinder);
await tester.pumpAndSettle();
// ログアウトしたことの確認
expect(mockFirebaseAuth.currentUser, isNull);
});
}
上記のテストコードのように、FirebaseAuth.instance をモックの MockFirebaseAuth に override することで、signOut のメソッドを、モックの signOut メソッドに切り替えることができます。
この override さえできてしまえば、あとはサンプルコードを参考にして、createUserWithEmailAndPassword や signInAnonymously など、ほかのFirebaseAuth のテストに応用することができると思われます。
終わりに
riverpod のドキュメントにも書いてありますが、
テスト時にモックやスタブを返すクラスに override することを前提にアプリを設計しておくことが、効率よくテストする上でとても重要だと感じました。
もし、間違っているところやよりよい方法をご存知の方がいれば、ご指摘いただけると助かります。