I am using Firebase Phone Auth in my Flutter project and want to test my auth class. I know how to use when()
and .thenAnswer()
from Mockito with typical Future
s.
I want to test my authentication method, in particular, verificationFailed
and verificationCompleted
callbacks.
Future<void> getSmsCodeWithFirebase() async {
try {
await _firebaseAuth.verifyPhoneNumber(
phoneNumber: fullPhoneNumber,
timeout: const Duration(seconds: 30),
verificationCompleted: (credential) async {
_firebaseSignIn(credential);
},
verificationFailed: (e) {
errorMessage = 'Error code: ${e.code}';
}
initModelState = DataState.error;
},
codeSent: (String verificationId, int resendToken) {
_firebaseSessionId = verificationId;
initModelState = DataState.idle;
},
codeAutoRetrievalTimeout: (String verificationId) {},
);
} catch (ex) {
errorMessage = 'There was some error';
updateModelState = DataState.error;
}
}
For now I came up with something like this, but I don't understand how to invoke passed callbacks.
test('cant verify phonenumber', () async {
when(mockFirebaseAuth.verifyPhoneNumber(
phoneNumber: any,
codeSent: anyNamed('codeSent'),
verificationCompleted: anyNamed('verificationCompleted'),
verificationFailed: anyNamed('verificationFailed'),
codeAutoRetrievalTimeout: anyNamed('codeAutoRetrievalTimeout')))
.thenAnswer((Invocation invocation) {
// I need to put something here?
});
await authCodeViewModel.getSmsCodeWithFirebase();
expect(authCodeViewModel.initModelState, DataState.error);
});
You're not really asking how to stub callbacks themselves; you're asking how to invoke callbacks for a stubbed method. You'd use captured callback arguments the same as any other captured arguments:
// Sample class with a method that takes a callback.
abstract class Foo {
void f(String Function(int x) callback, int y);
}
@GenerateMocks([Foo])
void main() {
var mockFoo = MockFoo();
mockFoo.f((x) => '$x', 42);
var captured = verify(mockFoo.f(captureAny, any)).captured;
var f = captured[0] as String Function(int);
print(f(88)); // Prints: 88
}
In your case, I think it'd be something like:
test('cant verify phonenumber', () async {
await authCodeViewModel.getSmsCodeWithFirebase();
var captured = verify(mockFirebaseAuth.verifyPhoneNumber(
phoneNumber: any,
codeSent: anyNamed('codeSent'),
verificationCompleted: anyNamed('verificationCompleted'),
verificationFailed: captureNamed('verificationFailed'),
codeAutoRetrievalTimeout: anyNamed('codeAutoRetrievalTimeout')))
.captured;
var verificationFailed = captured[0] as PhoneVerificationFailed;
verificationFailed(FirebaseAuthException());
expect(authCodeViewModel.initModelState, DataState.error);
});
Of course, if you're supplying the callbacks, you don't need to capture them in the first place; you can just invoke them directly yourself.