Reputation: 313
The unittest that I am writing should fail on exception and I would like to match the error thrown using a matcher, but I am getting an error.
What am I doing wrong currently and what is the error here? If I am doing it incorrectly, what is the correct way to test the error scenario for a method that returns a future? And why is there an asynchronous gap?
Here's the method I want to test :
Future<void> registerUser(String name, String email, String password) async {
auth.signUp(email, password, name).then((_) {
auth.getCurrentUser().then((user) async {
// Doing something
}).catchError((onError) {
throw onError;
});
Here's the test I have written :
test('should fail to register if fetching user fails', () async {
MockAuth auth = MockAuth();
RegisterRepository repo = RegisterRepository(auth);
String password = 'password';
String email = 'email';
String name = 'name';
when(auth.signUp(email, password, name))
.thenAnswer((_) => Future.value());
when(auth.getCurrentUser()).thenThrow((_) => throw Error());
try {
await repo.registerUser(name, email, password);
fail('exception not thrown');
} catch (e) {}
verify(auth.signUp(email, password, name)).called(1);
verify(auth.getCurrentUser()).called(1);
verifyNoMoreInteractions(auth);
});
I am getting this error :
package:mockito/src/mock.dart 403:7 PostExpectation.thenThrow.<fn>
package:mockito/src/mock.dart 130:45 Mock.noSuchMethod
package:dive/repository/register_repo.dart 25:12 RegisterRepository.registerUser.<fn>
===== asynchronous gap ===========================
dart:async Future.then
package:dive/repository/register_repo.dart 24:40 RegisterRepository.registerUser
test/repository/register_repo_test.dart 61:20 main.<fn>.<fn>
Closure: (dynamic) => Null
Upvotes: 3
Views: 4498
Reputation: 634
Just found that we can simply do this (check out the throwsA):
test("getNews SHOULD throw an exception WHEN api fails", () {
final ExceptionMock exception = ExceptionMock();
when(() => newsApi.getNews()).thenAnswer((realInvocation) => Future<List<JsonNews>>.error(exception));
expect(() => sut.getNews(), throwsA(exception));
});
Please notice, I'm mocking the exception. This way I'm confident that the api is actually being called. Otherwise I wouldn't catch that mocked exception. When using concrete object, one can't be sure if a value is being returned because the dependency actually returns that object or it is just hardcoded in the sun (system under test) implementation.
Upvotes: 1
Reputation: 313
For anyone else who faces this problem in the future,
Future<void> registerUser(String name, String email, String password) {
return auth
.signUp(email, password, name)
.then((_) => auth.getCurrentUser())
.then((user) {
// Doing something
}).catchError((onError) {
throw onError;
});
test('should fail to register if fetching user fails', () async {
MockAuth auth = MockAuth();
RegisterRepository repo = RegisterRepository(auth);
String password = 'password';
String email = 'email';
String name = 'name';
when(auth.signUp(email, password, name))
.thenAnswer((_) => Future.value());
when(auth.getCurrentUser()).thenAnswer((_) => Future.error('error'));
repo.registerUser(name, email, password).catchError((onError) {
expect(onError.toString(), 'error');
verify(auth.signUp(email, password, name)).called(1);
verify(auth.getCurrentUser()).called(1);
verifyNoMoreInteractions(auth);
});
});
The tests pass now.
Upvotes: 4