颤振测试中的假计时器

Posted

技术标签:

【中文标题】颤振测试中的假计时器【英文标题】:Fake timer in flutter tests 【发布时间】:2021-12-25 06:32:22 【问题描述】:

我在dataprovider中有这个方法:

  Future<String> getAccessToken(
    String code,
    DateTime created,
    Duration expiresIn,
    Duration interval,
  ) async 
    final uri = Uri.https(_host, '/oauth2/device', <String, String>
      'grant_type': 'device_token',
      'client_id': _clientId,
      'client_secret': _clientSecret,
      'code': code,
    );
    final headers = <String, String>'Content-Type': 'application/json';
    final response = await _client.post(uri, headers: headers);

    if (200 <= response.statusCode && response.statusCode < 400) 
      return response.body;
    

    final error = jsonDecode(response.body);

    final isExpired = DateTime.now().isAfter(created.add(expiresIn));
    if (isExpired || error['error'] == 'code_expired') 
      throw GetAccessTokenPollingException.fromJson(response.body);
    

    if (error['error'] == 'authorization_pending') 
      return Future.delayed(
        interval,
        () => getAccessToken(code, created, expiresIn, interval),
      );
    

    throw GetAccessTokenException.fromJson(response.body);
  

我想用error['error'] = 'authorization_pending'、duration = 60 秒和interval = 5 秒来检查 _client.post 在抛出 GetAccessTokenPollingException 之前被调用了 10 次,但我不知道该怎么做.

_client 是来自 http 包的模拟客户端,这里是未完成的测试:

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

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

    // expect(); what to do here?
    // - wait 60 seconds (is there any fake timer in dart tests?)
    // - check that _client.post is called 10 times
    // - check that next _client.post results with GetAccessTokenPollingException
  );

【问题讨论】:

package:fake_async 不幸的是,FakeAsync 无法控制 DateTime.now()(在 getAccessToken 方法中使用)或 Stopwatch 类报告的时间,因为它们不是 dart:async 的一部分。 【参考方案1】:

终于找到了解决办法。

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

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

  // - use small time for duration and interval to pass test faster
  // - if it's not an option, fake_async package can be used
  // - fake_async can't control the time reported by DateTime.now()
  //   since it's not part of dart:async.
  //   if DateTime.now() is used in test or testing method, replace it with clock.now()
  //   from clock package
  Future<String> getAccessToken() async => authDataProvider.getAccessToken(
        'code',
        DateTime.now(),
        const Duration(milliseconds: 50),
        const Duration(milliseconds: 20),
      );

  void verifyClientCalls() => verify(
        client.post(any, headers: anyNamed('headers')),
      ).called(3);

  // try/catch results with an exception in tests
  // should use except/throwsA to wrap an exception
  expect(
    () async => getAccessToken().whenComplete(verifyClientCalls),
    throwsA(isA<GetAccessTokenPollingException>()),
  );
);

【讨论】:

以上是关于颤振测试中的假计时器的主要内容,如果未能解决你的问题,请参考以下文章

颤振计时器仅更新秒小部件

当隔离被杀死时,颤振隔离内的计时器不会停止

当我执行代码+测试时,Azure 函数中的计时器触发器不起作用

能够将振动转发到手表的颤振振动包?

C++ 中的计时器

Flash 计时器中的文本动画