You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter单元测试:如何正确Mock GoogleSignIn并解决断言错误?

Flutter单元测试Google登录:解决'accessToken != null || idToken != null'断言错误

问题核心

这个断言错误是因为GoogleAuthProvider.credential()要求必须传入idToken或accessToken中的至少一个,你的Mock类没有正确返回这两个值,导致调用credential方法时参数全为空。

正确的Mock类实现

1. 修复MockGoogleSignInAuthentication

需要明确给idToken或accessToken赋值(二选一即可):

class MockGoogleSignInAuthentication extends Mock implements GoogleSignInAuthentication {
  // 固定返回一个模拟的ID令牌,也可以换成accessToken
  @override
  String? get idToken => 'mock-google-id-token';

  @override
  String? get accessToken => null;
}

2. 确保MockGoogleSignInAccount返回有效Authentication

让模拟的Google登录账号返回上面的Authentication实例:

class MockGoogleSignInAccount extends Mock implements GoogleSignInAccount {
  @override
  Future<GoogleSignInAuthentication> get authentication async => MockGoogleSignInAuthentication();
}

3. 让MockGoogleSignIn返回有效账号

确保模拟的GoogleSignIn类调用signIn()时返回上面的账号实例:

class MockGoogleSignIn extends Mock implements GoogleSignIn {
  @override
  Future<GoogleSignInAccount?> signIn() async => MockGoogleSignInAccount();

  // 如果业务代码用到静默登录,也要同步设置
  @override
  Future<GoogleSignInAccount?> signInSilently() async => MockGoogleSignInAccount();
}

测试代码调整

在测试用例中正确绑定Mock行为,并模拟Firebase的登录逻辑:

void main() {
  late MockFirebaseAuth mockFirebaseAuth;
  late MockGoogleSignIn mockGoogleSignIn;

  setUp(() {
    mockFirebaseAuth = MockFirebaseAuth();
    mockGoogleSignIn = MockGoogleSignIn();

    // 绑定GoogleSignIn的signIn行为
    when(mockGoogleSignIn.signIn()).thenAnswer((_) async => MockGoogleSignInAccount());

    // 模拟Firebase用Google凭证登录成功的场景
    final mockCredential = GoogleAuthProvider.credential(idToken: 'mock-google-id-token');
    when(mockFirebaseAuth.signInWithCredential(mockCredential))
        .thenAnswer((_) async => UserCredential(user: MockUser()));
  });

  test('Google登录流程测试', () async {
    // 注入Mock实例到业务类
    final authService = AuthService(
      firebaseAuth: mockFirebaseAuth,
      googleSignIn: mockGoogleSignIn,
    );

    // 执行登录方法
    final result = await authService.signInWithGoogle();

    // 断言验证
    expect(result, isNotNull);
    verify(mockGoogleSignIn.signIn()).called(1);
    verify(mockFirebaseAuth.signInWithCredential(any)).called(1);
  });
}

业务代码验证

确保业务代码中正确从GoogleSignInAccount获取Authentication并传入credential:

class AuthService {
  final FirebaseAuth _firebaseAuth;
  final GoogleSignIn _googleSignIn;

  AuthService({FirebaseAuth? firebaseAuth, GoogleSignIn? googleSignIn})
      : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance,
        _googleSignIn = googleSignIn ?? GoogleSignIn();

  Future<UserCredential?> signInWithGoogle() async {
    try {
      final googleUser = await _googleSignIn.signIn();
      if (googleUser == null) return null;

      final googleAuth = await googleUser.authentication;
      final credential = GoogleAuthProvider.credential(
        idToken: googleAuth.idToken,
        accessToken: googleAuth.accessToken,
      );

      return await _firebaseAuth.signInWithCredential(credential);
    } catch (e) {
      return null;
    }
  }
}

常见坑点排查

  • 不要将MockGoogleSignInAuthentication的idToken和accessToken同时设为null
  • 必须确保MockGoogleSignInAccount的authentication getter返回有效实例,不能留空
  • 测试前要通过when()正确绑定Mock类的行为,避免默认返回null

内容的提问来源于stack exchange,提问作者Yura

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 21:45:42