如何测试http Request对象相等性?如何用equatable处理http包对象?
解决http.Request/Response相等性测试问题
一、为什么http.Request相等性测试失败
http.Request类默认的==运算符是引用相等,即只有两个变量指向同一个对象实例时才会返回true。你创建的request和request2是两个独立的实例,哪怕内容完全一致,默认的equals匹配器也会判定它们不相等。
二、测试http.Request相等性的两种方案
方案1:自定义测试匹配器
直接编写一个自定义Matcher,对比Request的核心属性(method、url、body、headers等),实现内容相等的判断:
import 'package:http/http.dart' as http; import 'package:test/test.dart'; // 自定义匹配器,对比Request的核心属性 Matcher requestEquals(http.Request expected) => _RequestEqualsMatcher(expected); class _RequestEqualsMatcher extends Matcher { final http.Request _expected; _RequestEqualsMatcher(this._expected); @override bool matches(dynamic actual, Map matchState) { if (actual is! http.Request) return false; // 按需添加需要对比的属性,比如body、headers等 return actual.method == _expected.method && actual.url == _expected.url && actual.body == _expected.body && mapEquals(actual.headers, _expected.headers); } @override Description describe(Description description) { return description.add('Request: ${_expected.method} ${_expected.url}'); } } // 测试用例 test('equality test', () async { final uri = baseUri.replace(path: 'account/login'); final request = http.Request('POST', uri); final request2 = http.Request('POST', uri); // 使用自定义匹配器替代默认的equals expect(request, requestEquals(request2)); });
方案2:用Equatable包装Request类
通过包装第三方类,借助Equatable实现内容相等的判断:
import 'package:equatable/equatable.dart'; import 'package:http/http.dart' as http; // 包装http.Request,用Equatable管理相等性判断 class EquatableRequest extends Equatable { final http.Request request; const EquatableRequest(this.request); // 列出需要参与相等性判断的核心属性 @override List<Object?> get props => [ request.method, request.url, request.body, request.headers, ]; } // 测试用例 test('equality test', () async { final uri = baseUri.replace(path: 'account/login'); final request = http.Request('POST', uri); final request2 = http.Request('POST', uri); expect(EquatableRequest(request), equals(EquatableRequest(request2))); });
三、在http.Response上使用Equatable包
同样采用包装类的方式,将http.Response包裹后用Equatable管理相等性:
import 'package:equatable/equatable.dart'; import 'package:http/http.dart' as http; class EquatableResponse extends Equatable { final http.Response response; const EquatableResponse(this.response); @override List<Object?> get props => [ response.statusCode, response.body, response.headers, // 如果需要对比请求信息,可添加以下字段 response.request?.method, response.request?.url, ]; // 可选:添加getter简化属性访问 int get statusCode => response.statusCode; String get body => response.body; } // 测试示例 test('response equality test', () { final response1 = http.Response('{"success": true}', 200); final response2 = http.Response('{"success": true}', 200); expect(EquatableResponse(response1), equals(EquatableResponse(response2))); });
四、结合verify验证API调用正确性
如果用Mockito等mock库验证API调用,可以结合自定义匹配器来判断是否调用了正确的Request:
import 'package:http/http.dart' as http; import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; // Mock http.Client class MockClient extends Mock implements http.Client {} test('verify correct API endpoint is called', () async { final mockClient = MockClient(); final targetUri = baseUri.replace(path: 'account/login'); final expectedRequest = http.Request('POST', targetUri); // 设置mock返回 when(mockClient.send(argThat(requestEquals(expectedRequest)))) .thenAnswer((_) async => http.StreamedResponse( Stream.value([]), 200, )); // 调用你要测试的业务方法(该方法内部使用mockClient发送请求) await yourApiLoginFunction(mockClient); // 验证是否按预期调用了send方法 verify(mockClient.send(argThat(requestEquals(expectedRequest)))).called(1); });
内容的提问来源于stack exchange,提问作者zex_rectooor
相关产品推荐
相关产品推荐

