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

Dart单元测试verify调用不匹配:MockRequest相等性实现咨询

解决Http请求测试中的"No matching calls"问题

你遇到的核心问题是:测试中verify用的自定义MockRequest实例和sendEmail方法里生成的原生http.Request实例,默认情况下无法通过相等性校验,导致mockito判定调用不匹配。另外代码里还有个容易忽略的细节——请求头的大小写不一致,这也会影响匹配结果。

先修复请求头大小写问题

你的sendEmail方法里设置的请求头是"Content-type": "text/plain"(小写t),但测试中MockRequest的headers写的是'Content-Type': 'text/plain'(大写T)。虽然Http协议中请求头键不区分大小写,但Map的相等性比较是区分大小写的,这会直接导致匹配失败。先把测试里的请求头键改成和业务代码一致的"Content-type"。

方案一:用Equatable实现MockRequest的相等性校验

修改你的MockRequest类,通过EquatableMixin自定义相等性判断的字段,确保两个请求对象的核心属性一致时就判定为相等:

import 'package:equatable/equatable.dart';
import 'package:http/http.dart' as http;
import 'package:mockito/mockito.dart';

class MockRequest extends Mock with EquatableMixin implements http.Request {
  @override
  List<Object?> get props => [
    method,
    url,
    // 将HttpHeaders转为普通Map,并统一键为小写,避免大小写干扰
    Map.fromEntries(headers.entries.map((e) => MapEntry(e.key.toLowerCase(), e.value))),
    body,
  ];
}

这样修改后,只要两个请求的method、url、请求头(忽略大小写)、body都一致,MockRequest就会和原生http.Request判定为相等,verify就能匹配成功。

方案二:使用自定义匹配器(更灵活,无需MockRequest)

如果你不想引入Equatable,也可以直接用mockito的predicate自定义匹配逻辑,不用创建MockRequest实例:

  1. 在测试文件里定义匹配器函数:
import 'package:matcher/matcher.dart';
import 'package:http/http.dart' as http;

Matcher isExpectedRequest(Uri expectedUrl, String expectedEmail) {
  return predicate((http.Request actualRequest) {
    // 统一请求头键为小写,消除大小写差异
    final actualHeaders = actualRequest.headers.map((key, value) => MapEntry(key.toLowerCase(), value));
    
    return actualRequest.method == 'GET' &&
           actualRequest.url == expectedUrl &&
           actualHeaders['content-type'] == 'text/plain' &&
           actualRequest.body == '{"email":"$expectedEmail"}';
  }, "匹配预期的请求参数");
}
  1. 修改测试中的verify代码:
verify(() => client.send(argThat(isExpectedRequest(uri, validEmail)))).called(1);

这种方式直接验证send方法收到的实际请求对象是否符合预期,不需要额外创建MockRequest,逻辑更直观。

为什么原来的代码会失败?

mockito默认用==运算符比较传入的参数,而你在测试里创建的MockRequest实例和sendEmail里生成的原生http.Request实例是完全不同的对象,默认的==比较的是对象引用,所以即使属性一致,也会判定为不相等,导致出现"No matching calls"的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 00:42:48