颤振测试中的假计时器
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>()),
);
);
【讨论】:
以上是关于颤振测试中的假计时器的主要内容,如果未能解决你的问题,请参考以下文章