类型 'Null' 不是类型 'Future<UserCredential>' 的子类型

type 'Null' is not a subtype of type 'Future<UserCredential>'

首先强调一下,我是flutter的初学者,说的不对还请指正。我的任务是编写一些关于 firebase 中用户登录的单元测试。但是我没能使用 mockito 来模拟它,而且我不断收到一些错误。

class MockFirestore extends Mock implements FirebaseFirestore {}

class MockUserCredential extends Mock implements UserCredential {}

class MockFirebaseUser extends Mock implements User {}

class MockFirebaseAuth extends Mock implements FirebaseAuth {}

void main() {
  late UserAuthRemoteDataSourceImpl impl;
  late MockFirebaseAuth mockAuth;
  late MockFirestore mockFirestore;

  final credential = MockUserCredential();
  final user = MockFirebaseUser();

  setUp(() {
    mockAuth = MockFirebaseAuth();
    mockFirestore = MockFirestore();
    impl = UserAuthRemoteDataSourceImpl(mockAuth, mockFirestore);
  });

  test("Flutter test", () async {
    when(mockAuth.signInWithEmailAndPassword(
            email: "email", password: "password"))
        .thenAnswer((realInvocation) async => Future.value(credential));

    final result = await impl.signInUser("email", "password");
    expect(result, credential);
    verify(mockAuth.signInWithEmailAndPassword(
        email: "email", password: "password"));
  });
}

每当我 运行 这个测试用例时,我总是得到 type Null is not a subtype of type Future。我不确定我做错了什么。非常感谢您的帮助。提前致谢。

经过几个小时的研究和深入研究,我找到了解决方案。最初,模拟问题本身中提到的上述 类 。然后为 MockFirebaseAuth 覆盖您要从数据源访问的方法。例如,在我的例子中,用户使用电子邮件和密码登录,所以我所做的是,

class MockFirebaseAuth extends Mock implements FirebaseAuth {
  @override
  Future<UserCredential> signInWithEmailAndPassword({
    required String? email,
    required String? password,
  }) =>
      super.noSuchMethod(
          Invocation.method(#signInWithEmailAndPassword, [email, password]),
          returnValue: Future.value(MockUserCredential()));
}

之后使用 mockito 存根该方法

void main() {
  late UserAuthRemoteDataSourceImpl authRemoteDataSourceImpl;
  late MockFirebaseAuth mockAuth;
  late MockFirestore mockFirestore;
  late MockUserCredential mockCredential;
  late MockUser mockUser;

  setUp(() {
    mockAuth = MockFirebaseAuth();
    mockFirestore = MockFirestore();
    mockCredential = MockUserCredential();
    mockUser = MockUser();
    authRemoteDataSourceImpl =
        UserAuthRemoteDataSourceImpl(mockAuth, mockFirestore);
    when(mockCredential.user).thenReturn(mockUser); // IMPORTANT
  });
}

终于写出你想要的测试用例了。例如:

test("When valid password and emails are provided Should return a user details",
        () async {
      UserModel userModel = UserModel(email: "", displayName: "");

      when(mockAuth.signInWithEmailAndPassword(email: any, password: any))
          .thenAnswer((_) async => mockCredential);

      final result =
          await authRemoteDataSourceImpl.signInUser(testEmail, testPassword);
      expect(result, userModel);
      verify(mockAuth.signInWithEmailAndPassword(
          email: testEmail, password: testPassword));
    });