使用 Mocktail 测试模拟 http 客户端时,类型“Null”不是“Future<Response>”类型的子类型
Posted
技术标签:
【中文标题】使用 Mocktail 测试模拟 http 客户端时,类型“Null”不是“Future<Response>”类型的子类型【英文标题】:type 'Null' is not a subtype of type 'Future<Response>' when testing mocked http client with Mocktail 【发布时间】:2021-08-26 03:47:30 【问题描述】:我编写了一个简单的 HTTP get 测试,使用 Mocktail 来模拟 HTTP 客户端。当我在测试中调用 get 方法时,我收到“'Null' 类型不是'Future' 类型的子类型”。
有人知道为什么会这样吗?
这是测试:
class MockHttpClient extends Mock implements http.Client
void main()
late IdRemoteDataSourceImpl dataSource;
late MockHttpClient mockHttpClient;
setUp(
()
mockHttpClient = MockHttpClient();
dataSource = IdRemoteDataSourceImpl(client: mockHttpClient);
,
);
group('Get id', ()
test(
'when response code is 200',
() async
final url = Uri.parse('https://api.test.com/');
const tUsername = 'username';
final accountJson = json.decode(
fixture('account.json'),
// ignore: avoid_as
) as Map<String, dynamic>;
final tIdModel = IdModel.fromJson(accountJson);
// arrange
when(() => mockHttpClient.get(url))
.thenAnswer((_) async => http.Response(
fixture('account.json'),
200,
));
// act
final testResult = await dataSource.getId(tUsername);
// assert
// expect(testResult, tIdModel);
,
);
);
以下行运行时发生错误:
final testResult = await dataSource.getId(tUsername);
正在测试的代码:
import 'dart:convert';
import 'package:http/http.dart' as http;
class IdModel
IdModel(required this.id);
final String id;
factory IdModel.fromJson(Map<String, dynamic> json)
return IdModel(id: json['id'].toString());
abstract class IdRemoteDataSource
Future<IdModel> getId(String username);
class IdRemoteDataSourceImpl implements IdRemoteDataSource
IdRemoteDataSourceImpl(required this.client);
final http.Client client;
@override
Future<IdModel> getId(String username) async
final url = Uri.parse('https://api.test.com/query?username=$username');
final response = await client.get(url);
// ignore: avoid_as
final responseJson = json.decode(response.body) as Map<String, dynamic>;
return IdModel.fromJson(responseJson);
【问题讨论】:
【参考方案1】:错误type 'Null' is not a subtype of type 'Future'...
发生在您调用尚未为模拟对象实现的方法或传递给它的参数不同时。
在您的代码中,您将不同的 url 参数传递给 get(...)
方法。 Http客户端mock等待'https://api.test.com/'
但实际上'https://api.test.com/query?username=$username'
已经通过了。
你有两种选择来解决它。
-
将相同的 url 从
when(...)
传递给将在测试期间传递的模拟方法:
const tUsername = 'username';
final url = Uri.parse('https://api.test.com/query?username=$tUsername');
...
// arrange
when(() => mockHttpClient.get(url))
.thenAnswer((_) async => http.Response(
fixture('account.json'),
200,
),
);
-
使用
any
匹配器(如果你不关心传递了哪个参数):
registerFallbackValue(Uri.parse(''));
...
when(() => mockHttpClient.get(any()))
.thenAnswer((_) async => http.Response(
fixture('account.json'),
200,
),
);
【讨论】:
太棒了,您解决了我的问题并描述了它失败的原因 - 非常非常有帮助:-) 我确实发现在使用 any() 之前我需要将以下内容添加到测试设置中: registerFallbackValue( uri.parse('fake.url.com/')); 好!哦对了,你没看错,类型Uri需要注册FallbackValue。更新了我的答案 我有同样的问题,但我似乎正确地模拟了,因为我所有的测试都通过了。我在这里发布了我的问题:***.com/questions/69669624以上是关于使用 Mocktail 测试模拟 http 客户端时,类型“Null”不是“Future<Response>”类型的子类型的主要内容,如果未能解决你的问题,请参考以下文章
尝试使用 phpunit 模拟控制器内部的 http 客户端,但它不起作用