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

测试emitArray方法时Response.Success包裹列表后断言失败问题排查

解决Stream测试中包裹List的SuccessResponse相等性校验失败问题

你的问题核心确实出在SuccessResponse的==运算符实现上,具体来说是Dart中List的默认相等性判断逻辑导致的。

问题根源分析

你在测试代码中创建的Response.success(['test']),和emitArray方法里创建的Response.success(['test']),看起来内容完全一致,但它们的value是两个完全独立的List实例。Dart中List的默认==运算符是比较引用地址,而不是内容是否相同。你的SuccessResponse的==直接复用了value == other.value,这就导致两个看似相同的SuccessResponse实例会被判定为不相等,最终让expect断言失败。

两种可行的解决方案

方案一:修改SuccessResponse的相等性判断逻辑(通用型)

如果希望SuccessResponse能正确处理集合类型(List、Map、Set等)的内容相等性,可以借助collection包中的相等性工具类来实现:

  1. 首先在pubspec.yaml中添加collection依赖:
dependencies:
  collection: ^1.17.2 # 可以使用最新稳定版本
  1. 修改SuccessResponse的==和hashCode实现:
import 'package:collection/collection.dart';

class SuccessResponse<T> extends Response<T> {
  SuccessResponse(this.value): super._();
  final T value;

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    
    return other is SuccessResponse<T> &&
        runtimeType == other.runtimeType &&
        _areValuesEqual(value, other.value);
  }

  bool _areValuesEqual(T a, T b) {
    if (a is List && b is List) return const ListEquality().equals(a, b);
    if (a is Map && b is Map) return const MapEquality().equals(a, b);
    if (a is Set && b is Set) return const SetEquality().equals(a, b);
    // 其他自定义类型可以在这里扩展判断逻辑
    return a == b;
  }

  @override
  int get hashCode {
    if (value is List) return const ListEquality().hash(value);
    if (value is Map) return const MapEquality().hash(value);
    if (value is Set) return const SetEquality().hash(value);
    return value.hashCode;
  }

  @override
  String toString() {
    return 'SuccessResponse{value: $value}';
  }
}

这种方式让SuccessResponse对常见集合类型的相等性判断更符合直觉,不仅能解决当前测试的问题,后续其他场景使用也不会踩同样的坑。

方案二:在测试中使用内容匹配器(无需修改原代码)

如果不想改动SuccessResponse的实现,可以在测试里用test包提供的equals匹配器(它会递归比较对象内容,而非依赖==运算符),或者自定义断言逻辑:

void main() {
  ListResponse underTest;
  setUp(() {
    underTest = ListResponse();
  });
  
  test('It should emit array', () {
    expect(
      underTest.array,
      emitsInOrder([
        // 使用equals匹配器判断内容相等
        equals(Response.success(['test'])),
        emitsDone,
      ]),
    );
    underTest.emitArray();
    underTest.dispose();
  });
}

或者用更灵活的predicate来做自定义校验:

test('It should emit array', () {
  expect(
    underTest.array,
    emitsInOrder([
      predicate<SuccessResponse<List<String>>>((res) {
        return res.value.isNotEmpty && res.value.first == 'test';
      }, 'emits a SuccessResponse containing ["test"]'),
      emitsDone,
    ]),
  );
  underTest.emitArray();
  underTest.dispose();
});

验证效果

无论选择哪种方案,重新运行测试后,断言都会正确识别两个SuccessResponse实例的内容相等性,测试就能顺利通过了。

内容的提问来源于stack exchange,提问作者Juan Cruz Soler

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 16:47:52