如何在Flutter中模拟firebase_messaging?

6

你好,我正尝试模拟 Firebase Messaging 以获取令牌,但在测试时出现了错误,请问有人可以帮助我解决这个问题吗?此错误仅在测试中发生,而不是在模拟器或手机中。这里是我的setupFirebaseAuthMocks。谢谢。

我的测试:

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
}

void main() {
 setupFirebaseAuthMocks();
 late ProviderContainer container;

 group('AuthenticationControllerTest -', () {
   setUpAll(() async {
     await Firebase.initializeApp();
     FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
     registerThirdPartyServices();
   });
   tearDown(() {
    unregisterThirdPartyServices();
     //container.dispose();
});
    });

错误

MissingPluginException(No implementation found for method Messaging#getToken on channel plugins.flutter.io/firebase_messaging)

这是我正在尝试调用的方法

  Future<Result<Failure, bool>> registerUserFirebaseToken() async {
   try {
    log.i('Registering Firebase');
    final fireBaseMessaging = FirebaseMessaging.instance;
    final token = await fireBaseMessaging.getToken();
    log.v('Firebase token: $token');

  await api.post(
    link: '${env.getValue(kAuthUrl)}users/auth/firebase',
    body: {'token': token},
    hasHeader: true,
  );

  return const Success(true);
} catch (e) {
  return Error(Failure(message: 'Firebase registration went wrong, Please try again!', content: e.toString()));
}

}

1个回答

3

对于那些遇到相同问题的人,可以在官方 Firebase Messaging 的 Github 上找到一个 Mock 的示例

根据你使用的 Mockito 版本,你可能需要稍微更新一下这段代码。
这是我使用 Mockito v5.3.2 的 Mock 文件。

// ignore_for_file: require_trailing_commas

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart';
import 'package:firebase_messaging_platform_interface/firebase_messaging_platform_interface.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';

typedef Callback = Function(MethodCall call);

final MockFirebaseMessaging kMockMessagingPlatform = MockFirebaseMessaging();

Future<T> neverEndingFuture<T>() async {
  // ignore: literal_only_boolean_expressions
  while (true) {
    await Future.delayed(const Duration(minutes: 5));
  }
}

void setupFirebaseMessagingMocks() {
  TestWidgetsFlutterBinding.ensureInitialized();

  setupFirebaseCoreMocks();

  // Mock Platform Interface Methods
  // ignore: invalid_use_of_protected_member
  when(kMockMessagingPlatform.delegateFor(app: anyNamed('app')))
      .thenReturn(kMockMessagingPlatform);
  // ignore: invalid_use_of_protected_member
  when(kMockMessagingPlatform.setInitialValues(
    isAutoInitEnabled: anyNamed('isAutoInitEnabled'),
  )).thenReturn(kMockMessagingPlatform);
}

// Platform Interface Mock Classes

// FirebaseMessagingPlatform Mock
class MockFirebaseMessaging extends Mock
    with MockPlatformInterfaceMixin
    implements FirebaseMessagingPlatform {
  MockFirebaseMessaging() {
    TestFirebaseMessagingPlatform();
  }

  @override
  bool get isAutoInitEnabled {
    return super.noSuchMethod(Invocation.getter(#isAutoInitEnabled),
        returnValue: true, returnValueForMissingStub: true) as bool;
  }

  @override
  FirebaseMessagingPlatform delegateFor({FirebaseApp? app}) {
    return super.noSuchMethod(
      Invocation.method(#delegateFor, [], {#app: app}),
      returnValue: TestFirebaseMessagingPlatform(),
      returnValueForMissingStub: TestFirebaseMessagingPlatform(),
    ) as FirebaseMessagingPlatform;
  }

  @override
  FirebaseMessagingPlatform setInitialValues({bool? isAutoInitEnabled}) {
    return super.noSuchMethod(
      Invocation.method(
          #setInitialValues, [], {#isAutoInitEnabled: isAutoInitEnabled}),
      returnValue: TestFirebaseMessagingPlatform(),
      returnValueForMissingStub: TestFirebaseMessagingPlatform(),
    ) as FirebaseMessagingPlatform;
  }

  @override
  Future<RemoteMessage?> getInitialMessage() {
    return super.noSuchMethod(Invocation.method(#getInitialMessage, []),
            returnValue: neverEndingFuture<RemoteMessage>(),
            returnValueForMissingStub: neverEndingFuture<RemoteMessage>())
        as Future<RemoteMessage?>;
  }

  @override
  Future<void> deleteToken() {
    return super.noSuchMethod(Invocation.method(#deleteToken, []),
        returnValue: Future<void>.value(),
        returnValueForMissingStub: Future<void>.value()) as Future<void>;
  }

  @override
  Future<String?> getAPNSToken() {
    return super.noSuchMethod(Invocation.method(#getAPNSToken, []),
        returnValue: Future<String>.value(''),
        returnValueForMissingStub: Future<String>.value('')) as Future<String?>;
  }

  @override
  Future<String> getToken({String? vapidKey}) {
    return super.noSuchMethod(
        Invocation.method(#getToken, [], {#vapidKey: vapidKey}),
        returnValue: Future<String>.value(''),
        returnValueForMissingStub: Future<String>.value('')) as Future<String>;
  }

  @override
  Future<void> setAutoInitEnabled(bool? enabled) {
    return super.noSuchMethod(Invocation.method(#setAutoInitEnabled, [enabled]),
        returnValue: Future<void>.value(),
        returnValueForMissingStub: Future<void>.value()) as Future<void>;
  }

  @override
  Stream<String> get onTokenRefresh {
    return super.noSuchMethod(
      Invocation.getter(#onTokenRefresh),
      returnValue: const Stream<String>.empty(),
      returnValueForMissingStub: const Stream<String>.empty(),
    ) as Stream<String>;
  }

  @override
  Future<NotificationSettings> requestPermission(
      {bool? alert = true,
      bool? announcement = false,
      bool? badge = true,
      bool? carPlay = false,
      bool? criticalAlert = false,
      bool? provisional = false,
      bool? sound = true}) {
    return super.noSuchMethod(
            Invocation.method(#requestPermission, [], {
              #alert: alert,
              #announcement: announcement,
              #badge: badge,
              #carPlay: carPlay,
              #criticalAlert: criticalAlert,
              #provisional: provisional,
              #sound: sound
            }),
            returnValue: neverEndingFuture<NotificationSettings>(),
            returnValueForMissingStub:
                neverEndingFuture<NotificationSettings>())
        as Future<NotificationSettings>;
  }

  @override
  Future<void> subscribeToTopic(String? topic) {
    return super.noSuchMethod(Invocation.method(#subscribeToTopic, [topic]),
        returnValue: Future<void>.value(),
        returnValueForMissingStub: Future<void>.value()) as Future<void>;
  }

  @override
  Future<void> unsubscribeFromTopic(String? topic) {
    return super.noSuchMethod(Invocation.method(#unsubscribeFromTopic, [topic]),
        returnValue: Future<void>.value(),
        returnValueForMissingStub: Future<void>.value()) as Future<void>;
  }
}

class TestFirebaseMessagingPlatform extends FirebaseMessagingPlatform {
  TestFirebaseMessagingPlatform() : super();
}

这里是单元测试本身

void main() {

 setupFirebaseMessagingMocks();

  setUpAll(() async {
    await Firebase.initializeApp();
    FirebaseMessagingPlatform.instance = kMockMessagingPlatform;
  });

  test('An example of test', () {
      //...
      when(kMockMessagingPlatform.getToken(vapidKey: anyNamed('vapidKey')))
          .thenAnswer(
        (_) => Future.value('DEVICE_ID'),
      );
      //...
  });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接