Flutter中如何对Firebase用户重载的超时逻辑进行单元测试?
测试Firebase用户重载超时逻辑及方案选型问题解答
一、测试报错的原因及修复方案
你的测试报错主要有两个可修复的问题:
1. 异步方法抛异常的mock写法错误
mocktail中,thenThrow仅用于同步方法的异常模拟,对于返回Future的异步方法,你需要用thenAnswer返回一个携带异常的Future,否则异常会在调用阶段直接抛出,无法被getSignedInUser内部的try/catch捕获。
如果只需要验证异常被捕获的逻辑,可以直接修改mock写法:
when(() => firebaseAuthFacade.reloadCurrentUser()) .thenAnswer((_) async => throw TimeoutException('timeout', const Duration(seconds: 20)));
2. 更贴合真实场景的超时模拟方案
如果要模拟真实的超时触发场景(即reloadCurrentUser长时间未返回,由Future.timeout()主动抛出异常),可以使用Flutter测试的fakeAsync模拟时间流逝,不需要等待真实20秒:
test( '重载currentUser时触发超时,抛出TimeoutException后函数继续执行并返回optionOf封装的currentUser', () async { reset(fakeFirebaseAuth); reset(fakeFacebookAuth); reset(fakeGoogleSignIn); final currentUser = FakeUser(); // 模拟currentUser存在 when(() => fakeFirebaseAuth.currentUser).thenReturn(currentUser); // 模拟reload方法返回一个永远不完成的Future when(() => currentUser.reload()).thenAnswer((_) => Completer().future); final resultFuture = firebaseAuthFacade.getSignedInUser(); // 模拟时间流逝20秒,触发timeout fakeAsync((async) => async.elapse(const Duration(seconds: 20))); final result = await resultFuture; expect(result, isA<Some<User>>()); }, );
如果你的单元测试不依赖Flutter框架,可以单独使用clock包实现类似的假时间逻辑。
二、是否要移除超时逻辑改用连接性检测
不要直接移除超时逻辑,两种方案是互补关系而非替代关系:
- 连接性检测只能判断设备是否接入了网络,无法判断网络是否能正常访问Firebase服务(比如连接了无互联网的WiFi、防火墙拦截了Firebase请求等场景,连接性检测会判定为有网,但重载请求会一直挂起)
- 超时逻辑是兜底机制,能覆盖所有请求长时间未响应的场景,避免业务逻辑被永久卡住
推荐的优化方案是两者结合:
- 执行重载前先做连接性检测,如果确认无网络,直接跳过重载逻辑,返回本地缓存的当前用户,避免无意义的等待
- 保留原有的20秒超时逻辑,作为网络正常但服务不可达场景的兜底
内容的提问来源于stack exchange,提问作者Donatas
相关产品推荐
相关产品推荐

