Flutter-Mockito在尝试引发自定义异常时表现异常

时间:2018-09-11 13:38:25

标签: dart mockito flutter flutter-test

尝试使用Mockito测试我的BLoC,BLoC使用存储库类进行服务器调用,如果用户未通过身份验证,则服务器调用函数应该引发自定义异常。

但是,当我尝试对存储库函数进行存根以引发该自定义异常时,测试只会失败并显示以下错误:

sunapsis Authorization error (test error): test description

package:mockito/src/mock.dart 342:7                                     PostExpectation.thenThrow.<fn>
package:mockito/src/mock.dart 119:37                                    Mock.noSuchMethod
package:sunapsis/datasource/models/notifications_repository.dart 28:37  MockNotificationRepository.getNotificationList
package:sunapsis/blocs/notification_blocs/notification_bloc.dart 36:10  NotificationBloc.fetchNotifications
test/blocs/notification_blocs/notification_bloc_test.dart 53:48         main.<fn>.<fn>.<fn>
===== asynchronous gap ===========================
dart:async                                                              scheduleMicrotask
test/blocs/notification_blocs/notification_bloc_test.dart 53:7          main.<fn>.<fn>

这就是我的BLoC代码的样子:fetchNotifications函数调用存储库函数并处理响应和错误。有两个catchError块,一个处理AuthorizationException情况,另一个处理任何其他Exception。以不同的方式处理AuthorizationException,因为它将用于设置应用程序的Login状态。

notification_bloc.dart

import 'dart:async';

import 'package:logging/logging.dart';
import 'package:rxdart/rxdart.dart';
import 'package:sunapsis/datasource/dataobjects/notification.dart';
import 'package:sunapsis/datasource/models/notifications_repository.dart';
import 'package:sunapsis/utils/authorization_exception.dart';

class NotificationBloc {
  final NotificationsRepository _notificationsRepository;

  final Logger log = Logger('NotificationBloc');
  final _listNotifications = PublishSubject<List<NotificationElement>>();
  final _isEmptyList = PublishSubject<bool>();
  final _isLoggedIn = PublishSubject<bool>();

  Observable<List<NotificationElement>> get getNotificationList =>
      _listNotifications.stream;

  Observable<bool> get isLoggedIn => _isLoggedIn.stream;

  Observable<bool> get isEmptyList => _isEmptyList.stream;

  NotificationBloc({NotificationsRepository notificationsRepository})
      : _notificationsRepository =
            notificationsRepository ?? NotificationsRepository();

  void fetchNotifications() {
    _notificationsRepository
        .getNotificationList()
        .then((List<NotificationElement> list) {
          if (list.length > 0) {
            _listNotifications.add(list);
          } else {
            _isEmptyList.add(true);
          }
        })
        .catchError((e) => _handleErrorCase,
            test: (e) => e is AuthorizationException)
        .catchError((e) {
          log.shout("Error occurred while fetching notifications $e");
          _listNotifications.sink.addError("$e");
        });
  }
  void _handleErrorCase(e) {
     log.shout("Session invalid: $e");
     _isLoggedIn.sink.add(false);
     _listNotifications.sink.addError("Error");
 }
}

这是我的存储库代码的样子:

notifications_repository.dart

import 'dart:async';

import 'package:logging/logging.dart';
import 'package:sunapsis/datasource/dataobjects/notification.dart';
import 'package:sunapsis/datasource/db/sunapsis_db_provider.dart';
import 'package:sunapsis/datasource/network/api_response.dart';
import 'package:sunapsis/datasource/network/sunapsis_api_provider.dart';
import 'package:sunapsis/utils/authorization_exception.dart';

/// Repository class which makes available all notifications related API functions
/// for server calls and database calls
class NotificationsRepository {
  final Logger log = Logger('NotificationsRepository');
  final SunapsisApiProvider apiProvider;
  final SunapsisDbProvider dbProvider;

  /// Optional [SunapsisApiProvider] and [SunapsisDbProvider] instances expected for unit testing
  /// If instances are not provided - default case - a new instance is created
  NotificationsRepository({SunapsisApiProvider api, SunapsisDbProvider db})
      : apiProvider = api ?? SunapsisApiProvider(),
        dbProvider = db ?? SunapsisDbProvider();

  /// Returns a [Future] of [List] of [NotificationElement]
  /// Tries to first look for notifications on the db
  /// if notifications are found that list is returned
  /// else a server call is made to fetch notifications
  Future<List<NotificationElement>> getNotificationList([int currentTime]) {
    return dbProvider.fetchNotifications().then(
        (List<NotificationElement> notifications) {
      if (notifications.length == 0) {
        return getNotificationsListFromServer(currentTime);
      }
      return notifications;
    }, onError: (_) {
      return getNotificationsListFromServer(currentTime);
    });
  }
}

函数getNotificationsListFromServer应该抛出AuthorizationException,该函数应该通过getNotificationList传播

这是测试案例,失败了,并带有前面提到的错误:

test('getNotification observable gets error on AuthorizationException',
    () async {
  when(mockNotificationsRepository.getNotificationList())
      .thenThrow(AuthorizationException("test error", "test description"));
  scheduleMicrotask(() => notificationBloc.fetchNotifications());
  await expectLater(
      notificationBloc.getNotificationList, emitsError("Error"));
});

这是自定义异常的样子:

authorization_exception.dart

class AuthorizationException implements Exception {
  final String error;

  final String description;

  AuthorizationException(this.error, this.description);

  String toString() {
    var header = 'sunapsis Authorization error ($error)';
    if (description != null) {
      header = '$header: $description';
    }
    return '$header';
  }
}

PS:当我测试存储库类和引发自定义异常的函数时,这些测试已通过。

test('throws AuthorizationException on invalidSession()', () async {
  when(mockSunapsisDbProvider.fetchNotifications())
      .thenAnswer((_) => Future.error("Error"));
  when(mockSunapsisDbProvider.getCachedLoginSession(1536333713))
      .thenAnswer((_) => Future.value(authorization));
  when(mockSunapsisApiProvider.getNotifications(authHeader))
      .thenAnswer((_) => Future.value(ApiResponse.invalidSession()));
  expect(notificationsRepository.getNotificationList(1536333713),
      throwsA(TypeMatcher<AuthorizationException>()));
});

以上测试通过并按预期工作。

我是一名新的大学毕业生,正在担任我的第一个全职工作,我可能做错了什么。我将不胜感激任何反馈或帮助,一切都会有所帮助。感谢您调查这个问题。

1 个答案:

答案 0 :(得分:0)

我认为您使用的是错误的NoSuchFieldException类。您需要使用测试框架中的一种,而不是Flutter框架中的一种。

TypeMatcher