I'm learning about unit test for Flutter. I have a Sign In with Google functionality in my app as a package and I want to unit test it.
I'm half way there but I kinda stuck about what to do with this error.
'package:firebase_auth_platform_interface/src/providers/google_auth.dart': Failed assertion: line 43 pos 12: 'accessToken != null || idToken != null': At least one of ID token and access token is required
dart:core _AssertionError._throwNew
package:firebase_auth_platform_interface/src/providers/google_auth.dart 43:12 GoogleAuthProvider.credential
package:firebase_auth_client/src/firebase_auth_client.dart 107:45 FirebaseAuthClient.signInWithGoogle
===== asynchronous gap ===========================
dart:async _CustomZone.registerUnaryCallback
package:firebase_auth_client/src/firebase_auth_client.dart 97:26 FirebaseAuthClient.signInWithGoogle
test/src/firebase_auth_client_test.dart 101:30 main.<fn>.<fn>.<fn>
My test script look like this
class FakeUserCredential extends Fake implements UserCredential {}
class MockFirebaseAuth extends Mock implements FirebaseAuth {}
class MockGoogleSignIn extends Mock implements GoogleSignIn {}
class MockGoogleSignInAccount extends Mock implements GoogleSignInAccount {}
class MockGoogleSignInAuthentication extends Mock
implements GoogleSignInAuthentication {}
class MockOAuthCredential extends Mock implements OAuthCredential {}
void main() {
late FirebaseAuth firebaseAuth;
late UserCredential userCredential;
late FirebaseAuthClient firebaseAuthClient;
late GoogleSignIn googleSignIn;
late GoogleSignInAccount googleSignInAccount;
late GoogleSignInAuthentication googleSignInAuthentication;
late OAuthCredential oAuthCredential;
setUp(() {
firebaseAuth = MockFirebaseAuth();
userCredential = FakeUserCredential();
googleSignIn = MockGoogleSignIn();
googleSignInAccount = MockGoogleSignInAccount();
oAuthCredential = MockOAuthCredential();
googleSignInAuthentication = MockGoogleSignInAuthentication();
firebaseAuthClient = FirebaseAuthClient(
auth: firebaseAuth,
googleSignIn: googleSignIn,
);
});
group('FirebaseAuthClient', () {
// passing tests omitted...
group('SignIn', () {
// passing tests omitted...
test('with google completes', () async {
when(() => googleSignIn.signIn()).thenAnswer(
(_) async => googleSignInAccount,
);
when(() => googleSignInAccount.authentication).thenAnswer(
(_) async => googleSignInAuthentication,
);
when(
() => firebaseAuth.signInWithCredential(oAuthCredential),
).thenAnswer((_) async => userCredential);
expect(
firebaseAuthClient.signInWithGoogle(),
completes,
);
});
// passing tests omitted...
});
// passing tests omitted...
});
}
And this is the package I wrote.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
/// {@template firebase_auth_client_exception}
/// Abstract class to handle the firebase auth client exceptions.
/// {@endtemplate}
abstract class FirebaseAuthClientException implements Exception {
/// {@macro firebase_auth_client_exception}
const FirebaseAuthClientException(this.error);
/// The error which was caught.
final Object error;
}
/// {@template firebase_sign_in_failure}
/// Thrown during the sign in process if a failure occurs.
/// {@endtemplate}
class FirebaseSignInFailure extends FirebaseAuthClientException {
/// {@macro firebase_sign_in_failure}
const FirebaseSignInFailure(super.error);
/// Construct error messages from the given code.
factory FirebaseSignInFailure.fromCode(String code) {
switch (code) {
case 'invalid-email':
return const FirebaseSignInFailure(
'Email address is invalid.',
);
case 'user-disabled':
return const FirebaseSignInFailure(
'Your account is disabled.',
);
case 'user-not-found':
return const FirebaseSignInFailure(
'Unable to find your account.',
);
case 'wrong-password':
return const FirebaseSignInFailure(
'You have entered the wrong password.',
);
default:
return const FirebaseSignInFailure(
'An unknown error occurred.',
);
}
}
@override
String toString() => error.toString();
}
/// {@template firebase_sign_out_failure}
/// Thrown during the sign out process if a failure occurs.
/// {@endtemplate}
class FirebaseSignOutFailure extends FirebaseAuthClientException {
/// {@macro firebase_sign_out_failure}
const FirebaseSignOutFailure(super.error);
}
/// {@template firebase_auth_client}
/// Firebase auth client
/// {@endtemplate}
class FirebaseAuthClient {
/// {@macro firebase_auth_client}
const FirebaseAuthClient({
required FirebaseAuth auth,
required GoogleSignIn googleSignIn,
}) : _auth = auth,
_googleSignIn = googleSignIn;
final FirebaseAuth _auth;
final GoogleSignIn _googleSignIn;
// unrelated methods omitted...
/// Sign the user in using Google auth provider.
Future<UserCredential> signInWithGoogle() async {
try {
final googleUser = await _googleSignIn.signIn();
final googleAuth = await googleUser?.authentication;
if (googleAuth == null) {
Error.throwWithStackTrace(
const FirebaseSignInFailure('Sign In Cancelled.'),
StackTrace.current,
);
}
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
return await _auth.signInWithCredential(credential);
} on FirebaseException catch (error, stackTrace) {
Error.throwWithStackTrace(
FirebaseSignInFailure.fromCode(error.code),
stackTrace,
);
} catch (error, stackTrace) {
Error.throwWithStackTrace(FirebaseSignInFailure(error), stackTrace);
}
}
// unrelated methods omitted...
}
I once tried to override the properties of the MockGoogleSignInAuthentication
like this, but it doesn't work.
class MockGoogleSignInAuthentication extends Mock
implements GoogleSignInAuthentication {
@override
String? get idToken => 'fakeId';
@override
String? get accessToken => 'fakeToken';
}
Can somebody please point me to the right direction for this? Thanks in advance!
CodePudding user response:
You can use google_sign_in mocks package for google auth mock
CodePudding user response:
For those who are wondering about how I implement the test using the package mentioned by user SHYAM.
Here is how my full test script look like.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_auth_client/firebase_auth_client.dart';
import 'package:firebase_auth_mocks/firebase_auth_mocks.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:google_sign_in_mocks/google_sign_in_mocks.dart';
import 'package:mocktail/mocktail.dart';
void main() {
late FirebaseAuth firebaseAuth;
late FirebaseAuthClient firebaseAuthClient;
late GoogleSignIn googleSignIn;
const email = '[email protected]';
const password = 'password';
setUp(() {
final user = MockUser(email: email);
firebaseAuth = MockFirebaseAuth(mockUser: user);
googleSignIn = MockGoogleSignIn();
firebaseAuthClient = FirebaseAuthClient(
auth: firebaseAuth,
googleSignIn: googleSignIn,
);
});
group('FirebaseAuthClient', () {
test('can be instantiated', () {
expect(
FirebaseAuthClient(
auth: firebaseAuth,
googleSignIn: googleSignIn,
),
isNotNull,
);
});
group('SignIn', () {
test('with an email completes', () async {
expect(
firebaseAuthClient.signInWithEmail(email: email, password: password),
completes,
);
});
test('with an email throw FirebaseAuthSignInFailure', () async {
when(
() => firebaseAuth.signInWithEmailAndPassword(
email: email,
password: password,
),
).thenThrow(Exception('oops'));
expect(
firebaseAuthClient.signInWithEmail(email: email, password: password),
throwsA(isA<FirebaseSignInFailure>()),
);
});
test('with google completes', () async {
expect(
firebaseAuthClient.signInWithGoogle(),
completes,
);
});
test('with google throws FirebaseSignInFailure', () async {
when(
() => firebaseAuth.signInWithProvider(GoogleAuthProvider()),
).thenThrow(Exception('oops'));
expect(
firebaseAuthClient.signInWithGoogle(),
throwsA(isA<FirebaseSignInFailure>()),
);
});
});
group('SignOut', () {
test('on completes', () async {
expect(
firebaseAuthClient.signOut(),
completes,
);
});
test('throw FirebaseSignOutFailure', () async {
when(
() => firebaseAuth.signOut(),
).thenThrow(Exception('oops'));
expect(
firebaseAuthClient.signOut(),
throwsA(isA<FirebaseSignOutFailure>()),
);
});
});
});
}