0

I'm writing my first flutter unit test of my code. The test passes initially but I'm getting two errors:

MissingPluginException(No implementation found for method Auth#registerChangeListeners on channel plugins.flutter.io/firebase_auth)

and:

This test failed after it had already completed. Make sure to use [expectAsync]
or the [completes] matcher when testing async code.

It doesn't help that flutter seems to have updated the tests dramatically recently by not even using flutter_test anymore, and using test instead. The firebase mock that I found online is using flutter_test.

This is the full error:

ProviderContainer.read
package:riverpod/…/framework/container.dart:125
ProviderElement.read
package:riverpod/…/framework/base_provider.dart:584
authenticationStatusServiceProvider.<fn>
package:vepo/…/current_authentication_status/current_authentication_status_service.dart:10
ProviderElement._runStateCreate
package:riverpod/…/framework/base_provider.dart:873
ProviderElement.mount
package:riverpod/…/framework/base_provider.dart:801
ProviderContainer.readProviderElement.<fn>
package:riverpod/…/framework/container.dart:308
dart:collection                                                                                                       _HashMap.putIfAbsent
ProviderContainer.readProviderElement
package:riverpod/…/framework/container.dart:287
ProviderContainer.read
package:riverpod/…/framework/container.dart:125
main.<fn>.<fn>
test/…/services/current_authentication_status_service_test.dart:21
2

This test failed after it had already completed. Make sure to use [expectAsync]
or the [completes] matcher when testing async code.
MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:157
===== asynchronous gap ===========================
dart:async                                                                                                            _asyncThenWrapperHelper
MethodChannel.invokeMethod
package:flutter/…/services/platform_channel.dart:332
new MethodChannelFirebaseAuth
package:firebase_auth_platform_interface/…/method_channel/method_channel_firebase_auth.dart:72
MethodChannelFirebaseAuth.delegateFor
package:firebase_auth_platform_interface/…/method_channel/method_channel_firebase_auth.dart:238
new FirebaseAuthPlatform.instanceFor
package:firebase_auth_platform_interface/…/platform_interface/platform_interface_firebase_auth.dart:43
FirebaseAuth._delegate
package:firebase_auth/src/firebase_auth.dart:23
FirebaseAuth.authStateChanges
package:firebase_auth/src/firebase_auth.dart:247
CurrentUserService.onCreate
package:vepo/…/current_user/current_user_service.dart:27
new CurrentUserService
package:vepo/…/current_user/current_user_service.dart:17
currentUserServiceProvider.<fn>
package:vepo/…/current_user/current_user_service.dart:9
ProviderElement._runStateCreate
package:riverpod/…/framework/base_provider.dart:873
ProviderElement.mount
package:riverpod/…/framework/base_provider.dart:801
ProviderContainer.readProviderElement.<fn>
package:riverpod/…/framework/container.dart:308
dart:collection                                                                                                       _HashMap.putIfAbsent
ProviderContainer.readProviderElement
package:riverpod/…/framework/container.dart:287
ProviderContainer.read
package:riverpod/…/framework/container.dart:125
ProviderElement.read
package:riverpod/…/framework/base_provider.dart:584
authenticationStatusServiceProvider.<fn>
package:vepo/…/current_authentication_status/current_authentication_status_service.dart:10
ProviderElement._runStateCreate
package:riverpod/…/framework/base_provider.dart:873
ProviderElement.mount
package:riverpod/…/framework/base_provider.dart:801
ProviderContainer.readProviderElement.<fn>
package:riverpod/…/framework/container.dart:308
dart:collection                                                                                                       _HashMap.putIfAbsent
ProviderContainer.readProviderElement
package:riverpod/…/framework/container.dart:287
ProviderContainer.read
package:riverpod/…/framework/container.dart:125
main.<fn>.<fn>
test/…/services/current_authentication_status_service_test.dart:21
2

✓ CurrentAuthenticationStatusService String.split() splits the string on the delimiter
Exited (1)

[UPDATED] The test:

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:test/test.dart';
import 'package:vepo/src/application/services/current_authentication_status/current_authentication_status_service.dart';
import 'package:vepo/src/common/enums/authentication_status_enum.dart';

import 'firebase_mock.dart';

void main() {
  setupCloudFirestoreMocks();

  setUpAll(() async {
    WidgetsFlutterBinding.ensureInitialized();

    await Firebase.initializeApp();
  });
  group('CurrentAuthenticationStatusService', () {
    test('status gets the current authentication status of the user', () async {
      final authenticationStatusService =
          ProviderContainer().read(authenticationStatusServiceProvider);
      authenticationStatusService.status.listen(
        expectAsync1(
          (event) {
            expect(event, AuthenticationStatusEnum.unauthenticated);
          },
        ),
      );
    });
  });
}

This is the code under test:

import 'dart:async';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:vepo/src/application/services/current_user/current_user_service.dart';
import 'package:vepo/src/common/enums/authentication_status_enum.dart';

final authenticationStatusServiceProvider =
    Provider<CurrentAuthenticationStatusService>((ref) {
  final _authenticationStatuseService =
      CurrentAuthenticationStatusService(ref.read(currentUserServiceProvider));
  ref.onDispose(() => _authenticationStatuseService.onClose());
  return _authenticationStatuseService;
});

/// This service holds the current authentication status of the current user.
class CurrentAuthenticationStatusService {
  CurrentAuthenticationStatusService(this._currentUserService)
      : assert(_currentUserService != null);

  final _authenticationStatusStreamController =
      StreamController<AuthenticationStatusEnum>();
  final CurrentUserService _currentUserService;

  void onClose() => _authenticationStatusStreamController.close();

  Stream<AuthenticationStatusEnum> get status async* {
    // await FirebaseAuth.instance.signOut();
    if (_currentUserService.currentUser.id != null) {
      yield AuthenticationStatusEnum.authenticated;
    } else {
      yield AuthenticationStatusEnum.unauthenticated;
    }
    yield* _authenticationStatusStreamController.stream;
  }
}

I have created this firebase mock which the test is using:

// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

typedef Callback = void Function(MethodCall call);

dynamic setupCloudFirestoreMocks([Callback customHandlers]) {
  TestWidgetsFlutterBinding.ensureInitialized();

  MethodChannelFirebase.channel.setMockMethodCallHandler((call) async {
    if (call.method == 'Firebase#initializeCore') {
      return [
        {
          'name': defaultFirebaseAppName,
          'options': {
            'apiKey': '123',
            'appId': '123',
            'messagingSenderId': '123',
            'projectId': '123',
          },
          'pluginConstants': <String, dynamic>{},
        }
      ];
    }

    if (call.method == 'Firebase#initializeApp') {
      return <String, dynamic>{
        'name': call.arguments['appName'],
        'options': call.arguments['options'],
        'pluginConstants': <String, dynamic>{},
      };
    }

    if (customHandlers != null) {
      customHandlers(call);
    }

    return null;
  });
}

Any idea why the errors? I get the same ones when running my second unit test also. It almost doesn't seem like an issue with the tests since it is the same errors and both of the tests pass.

4

0 回答 0