【问题标题】:How to test whether multiple Streams emit in a specific order?如何测试多个 Streams 是否按特定顺序发出?
【发布时间】:2019-09-15 07:51:54
【问题描述】:

我想验证多个 Streams 是否按特定顺序发出元素。

让我们采用以下 2 个 Streams。

Stream<String> data;
Stream<SomeStatus> status;

使用emitsInOrder 可以执行以下操作:

expect(data, emitsInOrder(["a", "b", "c"]));
expect(status, emitsInOrder([SomeStatus.loading, SomeStatus.connected, SomeStatus.disconnected]));

但是我怎样才能轻松地测试这样的东西:

Map map = {"data": data, "status": status};
expect(map, emitsInOrder([
   {"status": SomeStatus.loading},
   {"status": SomeStatus.connected},
   {"data": "a"},
   ...  // you get the idea
]);

谢谢

编辑:我已将解决此问题的尝试添加为答案,并希望得到任何反馈。

【问题讨论】:

    标签: dart flutter flutter-test rxdart


    【解决方案1】:

    这是我想出的:

    import 'dart:async';
    import 'package:rxdart/rxdart.dart';
    import 'package:test/test.dart';
    
    class StreamKey<T> {
    
        final String key;
    
        final Stream<T> stream;
    
        const StreamKey(this.key, this.stream);
    
        StreamEventType emitted(T t) => StreamEmitted(key, t);
    
        StreamEventType done() => StreamDone(key);
    
        StreamEventType errored(dynamic error) => StreamErrored(key, error);
    }
    
    void expectStreamsInOrder(List<StreamKey> keys, dynamic matcher) {
        Map<String, StreamSubscription> subs = {};
    
        expect(keys.map((a) => a.key).toSet().length, keys.length, reason: "Keys need to be unique");
    
        PublishSubject<StreamEventType> s = PublishSubject();
    
        expect(s, matcher);
    
        void checkEmpty() {
            assert(!s.isClosed);
            if(subs.values.isEmpty) {
                s.close();
            }
        }
    
        keys.forEach((key) {
            subs[key.key] = key.stream.listen(
                    (data) {
                    s.add(key.emitted(data));
                },
                onError: (error) {
                    s.add(key.errored(error));
                    subs.remove(key.key).cancel();
                    checkEmpty();
                },
                onDone: () {
                    s.add(key.done());
                    subs.remove(key.key).cancel();
                    checkEmpty();
                },
            );
        });
    }
    
    abstract class StreamEventType {
        final String key;
    
        const StreamEventType(this.key);
    }
    
    class StreamEmitted<T> extends StreamEventType {
    
        final T data;
    
        StreamEmitted(String key, this.data) : super(key);
    
        @override
        bool operator ==(Object other) =>
            identical(this, other) ||
                other is StreamEmitted &&
                    runtimeType == other.runtimeType &&
                    key == other.key &&
                    data == other.data;
        @override
        int get hashCode => data.hashCode ^ key.hashCode;
    
        @override
        String toString() => 'StreamEmitted{key: $key, data: $data}';
    }
    
    class StreamDone extends StreamEventType {
    
        StreamDone(String key) : super(key);
    
        @override
        bool operator ==(Object other) =>
            identical(this, other) ||
                other is StreamDone &&
                    key == other.key &&
                    runtimeType == other.runtimeType;
    
        @override
        int get hashCode => key.hashCode;
    
        @override
        String toString() => 'StreamDone{key: $key}';
    }
    
    class StreamErrored extends StreamEventType {
    
        final dynamic error;
    
        StreamErrored(String key, this.error) : super(key);
    
        @override
        bool operator ==(Object other) =>
            identical(this, other) ||
                other is StreamErrored &&
                    runtimeType == other.runtimeType &&
                    key == other.key &&
                    error == other.error;
    
        @override
        int get hashCode => error.hashCode ^ key.hashCode;
    
        @override
        String toString() => 'StreamErrored{key: $key, error: $error}';
    }
    

    import 'package:rxdart/rxdart.dart';
    import 'package:test/test.dart';
    
    import 'streams_in_order.dart';
    
    void main() {
        group("$expectStreamsInOrder", () {
            Subject<String> data; // ignore: close_sinks
            Subject<SomeStatus> status; // ignore: close_sinks
            StreamKey<String> keyData;
            StreamKey<SomeStatus> keyStatus;
    
            setUp(() {
                data = PublishSubject(sync: true);
                status = PublishSubject(sync: true);
                keyData = StreamKey("data", data);
                keyStatus = StreamKey("status", status);
            });
    
            test("example", () async {
                expectStreamsInOrder([keyData, keyStatus], emitsInOrder([
                    keyStatus.emitted(SomeStatus.loading),
                    keyStatus.emitted(SomeStatus.connected),
                    keyData.emitted("a"),
                    keyStatus.emitted(SomeStatus.disconnected),
                    keyData.done(),
                    keyStatus.done(),
                    emitsDone,
                ]));
    
                status.add(SomeStatus.loading);
                status.add(SomeStatus.connected);
                data.add("a");
                status.add(SomeStatus.disconnected);
                await data.close();
                await status.close();
            });
    
    
            test("example with error", () async {
                expectStreamsInOrder([keyData, keyStatus], emitsInOrder([
                    keyStatus.emitted(SomeStatus.loading),
                    keyStatus.emitted(SomeStatus.connected),
                    keyData.emitted("a"),
                    keyStatus.emitted(SomeStatus.disconnected),
                    keyData.errored("err1"),
                    keyStatus.errored("err2"),
                    emitsDone,
                ]));
    
                status.add(SomeStatus.loading);
                status.add(SomeStatus.connected);
                data.add("a");
                status.add(SomeStatus.disconnected);
                data.addError("err1");
                status.addError("err2");
            });
    
            test("-", () async {
                expectStreamsInOrder([keyData, keyStatus], emitsInOrder([
                    keyData.emitted("aa"),
                    keyStatus.emitted(SomeStatus.loading),
                    keyData.errored(123),
                    keyStatus.done(),
                    emitsDone,
                ]));
    
                data.add("aa");
                status.add(SomeStatus.loading);
                data.addError(123);
                await status.close();
            });
    
            test("-", () async {
                expectStreamsInOrder([keyData, keyStatus], emitsInOrder([
                    keyData.emitted("aa"),
                    keyStatus.emitted(SomeStatus.loading),
                    keyStatus.done(),
                    keyData.errored(123),
                    emitsDone,
                ]));
    
                data.add("aa");
                status.add(SomeStatus.loading);
                await status.close();
                data.addError(123);
            });
        });
    }
    
    enum SomeStatus {
        loading,
        connected,
        disconnected,
    }
    

    【讨论】:

      猜你喜欢
      • 2021-09-01
      • 2015-12-18
      • 2014-07-13
      • 2018-08-21
      • 2010-09-05
      • 2014-08-06
      • 1970-01-01
      • 2023-01-08
      相关资源
      最近更新 更多