【问题标题】:Test stream with wrapped array带有包装数组的测试流
【发布时间】:2020-06-03 18:06:11
【问题描述】:

我正在尝试测试函数 emitArray 发出 Response.Success 其值为 ['test']
如果我发出 List<String> 一切都按预期工作,但是一旦我将结果列表包装在 Response<List<String>> 中,测试就会失败。

结果已发出,但与预期结果比较时失败。
我想知道它是否与Response.Success中的==的实现有关,我使用的是IDE提供的默认实现。

这不是我拥有的真实代码,它只是一个更容易理解以尝试识别问题的简单示例。

这是我要测试的课程:

class ListResponse {
  final _array = BehaviorSubject<Response<List<String>>>();

  Stream<Response<List<String>>> get array => _array.stream;

  Future<void> emitArray() async {
    _array.add(Response.success(['test']));
  }

  void dispose() {
    _array.close();
  }
}

这是我的测试:

void main() {
  ListResponse underTest;
  setUp(() {
    underTest = ListResponse();
  });

  test('It should emit array', () {
    final array = Response.success(['test']);

    expect(
      underTest.array,
      emitsInOrder([
        array,
        emitsDone,
      ]),
    );

    underTest.emitArray();

    underTest.dispose();
  });
}

这是它抛出的错误:

Expected: should do the following in order:
          • emit an event that SuccessResponse<List<String>>:<SuccessResponse{value: [test]}>
          • be done
  Actual: <Instance of 'BehaviorSubject<Response<List<String>>>'>
   Which: emitted • SuccessResponse{value: [test]}
                  x Stream closed.
            which didn't emit an event that SuccessResponse<List<String>>:<SuccessResponse{value: [test]}>

这是响应类

class Response<T> {
  Response._();

  factory Response.success(T value) = SuccessResponse<T>;
  factory Response.error(Exception error) = ErrorResponse<T>;
}

class ErrorResponse<T> extends Response<T> {
  ErrorResponse(this.error): super._();

  final Exception error;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
          other is ErrorResponse &&
              runtimeType == other.runtimeType &&
              error == other.error;

  @override
  int get hashCode => error.hashCode;

  @override
  String toString() {
    return 'ErrorResponse{error: $error}';
  }
}

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

  final T value;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
          other is SuccessResponse &&
              runtimeType == other.runtimeType &&
              value == other.value;

  @override
  int get hashCode => value.hashCode;

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

【问题讨论】:

    标签: dart flutter-test rxdart


    【解决方案1】:

    我想知道它是否与Response.Success中==的实现有关

    没错。此特定测试失败,因为您无法将列表与== 进行比较:

    abstract class List<E> implements EfficientLengthIterable<E> {
      ...
      /**
      * Whether this list is equal to [other].
      *
      * Lists are, by default, only equal to themselves.
      * Even if [other] is also a list, the equality comparison
      * does not compare the elements of the two lists.
      */
     bool operator ==(Object other);
    }
    

    作为一种解决方法,您可以更改实现以比较对象的字符串表示:

      @override
      bool operator ==(Object other) =>
          identical(this, other) ||
          other is SuccessResponse &&
              runtimeType == other.runtimeType &&
              value.toString() == other.value.toString();
    
    

    有趣的是,传递未包装的List&lt;String&gt;s 对象通过了测试。这是因为StreamMatcher 使用来自matcher 包的equals() 来匹配事件,以及equals() can match lists and maps。它首先尝试与==匹配对象,然后检查它们是否是Iterable/Set/Map(并递归地深度匹配它们),然后报告不匹配错误。

    【讨论】:

    • 奇怪的是,如果我返回List&lt;String&gt; 而不是Response&lt;List&lt;String&gt;&gt;,测试就会通过,所以它会比较这种情况下的值。但是您的解决方案在这种情况下有效,谢谢!
    • @JuanCruzSoler 是的,这是真的。有趣的行为。我没有进一步调查它,但我认为 StreamMatcher 匹配事件的字符串表示。不过,如果这种情况下,它应该与注释掉的操作员覆盖一起工作,但它不会......
    • @JuanCruzSoler 添加了对该行为的解释。
    猜你喜欢
    • 2019-10-10
    • 1970-01-01
    • 1970-01-01
    • 2012-07-28
    • 2020-09-09
    • 1970-01-01
    • 2012-05-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多