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

Flutter测试中如何用Fake timer验证getAccessToken轮询逻辑

Dart官方生态提供了完整的假时间模拟能力,不需要真实等待即可完成测试,实现步骤如下:

实现方案

1. 依赖准备

你需要添加两个开发依赖到pubspec.yaml的dev_dependencies节点:

  • clock:官方提供的时间抽象层,用来替换硬编码的DateTime.now(),方便测试时注入假时间
  • fake_async:官方提供的假时间调度工具,可以模拟时间流逝、快进所有异步延迟,不需要真实等待

2. 生产代码改造

你现有代码里的时间判断用了硬编码的DateTime.now(),需要替换为clock包提供的可注入时间:

// 先导入clock包
import 'package:clock/clock.dart';

// 把原来的时间判断行
// final isExpired = DateTime.now().isAfter(created.add(expiresIn));
// 替换为
final isExpired = clock.now().isAfter(created.add(expiresIn));

3. 完整测试代码实现

用fake_async包裹测试逻辑,模拟时间流逝,同时用mock框架的verify方法验证调用次数即可:

import 'package:fake_async/fake_async.dart';
import 'package:clock/clock.dart';

test('getAccessToken polling', () {
  fakeAsync((async) {
    // 初始化MockClient
    final client = MockClient();
    when(client.post(any, headers: anyNamed('headers'))).thenAnswer(
      (_) async => Response('{"error": "authorization_pending"}', 400),
    );

    final authDataProvider = AuthenticationDataprovider(
      'clientId',
      'clientSecret',
      'host',
      client,
    );

    // 记录方法抛出的异常
    Object? thrownError;
    // 注入固定初始时间调用方法,不需要await,fakeAsync会控制异步调度
    final future = withClock(
      Clock(() => DateTime(2024, 1, 1, 0, 0, 0)),
      () => authDataProvider.getAccessToken(
        'test_code',
        DateTime(2024, 1, 1, 0, 0, 0),
        const Duration(seconds: 60),
        const Duration(seconds: 5),
      ),
    );
    future.catchError((e) => thrownError = e);

    // 第一次调用立即执行,验证首次调用
    verify(client.post(any, headers: anyNamed('headers'))).called(1);
    expect(thrownError, isNull);

    // 每次快进5秒,验证调用次数
    for (int i = 1; i <= 9; i++) {
      async.elapse(const Duration(seconds: 5));
      verify(client.post(any, headers: anyNamed('headers'))).called(i + 1);
      expect(thrownError, isNull);
    }

    // 最后快进到超过60秒有效期
    async.elapse(const Duration(seconds: 15));
    // 验证最终抛出预期异常
    expect(thrownError, isA<GetAccessTokenPollingException>());
    // 验证累计调用次数符合预期
    verify(client.post(any, headers: anyNamed('headers'))).called(10);
    verifyNoMoreInteractions(client);
  });
});

核心说明

  • fake_async会接管所有的Future.delayed调度,你调用elapse方法快进时间的时候,所有到期的延迟任务会立即执行,不需要真实等待时间,整个测试运行只需要几毫秒
  • 用clock包替换硬编码的DateTime.now()是必须的,否则你的过期时间判断用的还是系统真实时间,假时间不会生效
  • 你可以根据自己的实际业务逻辑调整循环次数和快进时长,验证调用次数直接用mock框架的verify方法即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 01:45:03