Тестирование класса Dart, выполняющего код на Isolate - PullRequest
0 голосов
/ 14 июля 2020

У меня есть класс Dart, который выполняет вычисления на Isolate. Вот мой код:

class Mapper {
  SendPort _isolateSendPort;
  Isolate _isolate;

  Mapper() {
    _asyncInit();
  }

  void _asyncInit() async {
    final receivePort = ReceivePort();
    _isolate = await Isolate.spawn(
      _mappingFunction,
      receivePort.sendPort,
    );
    _isolateSendPort = await receivePort.first;
  }

  static void _mappingFunction(SendPort callerSendPort) {
    final newIsolateReceivePort = ReceivePort();
    callerSendPort.send(newIsolateReceivePort.sendPort);

    newIsolateReceivePort.listen((dynamic message) {
        final crossIsolatesMessage =
          message as CrossIsolatesMessage<Input>;

        // some computations...

        crossIsolatesMessage.sender.send(output);
    });
  }

  Future<Output> map(Input input) async {
    final port = ReceivePort();
    _isolateSendPort.send(CrossIsolatesMessage<Input>(
      sender: port.sendPort,
      message: input,
    ));
    return port.map((event) => event as Output).first;
  }

  void dispose() {
    _isolate?.kill(priority: Isolate.immediate);
    _isolate = null;
  }
}

class CrossIsolatesMessage<T> {
  final SendPort sender;
  final T message;

  CrossIsolatesMessage({
    @required this.sender,
    this.message,
  });
}

Этот код хорошо работает, когда я запускаю приложение Flutter. Но модульный тест для publi c method Future<Output> map(Input input) выдает ошибку NoSuchMethodError, которая означает, что _isolateSendPort имеет значение null.

Вот код модульного теста:

test('Mapper map', () {
  final sut = Mapper();
  final inputDummy = Input('123');
  final resultFuture = sut.map(inputDummy);
  final expectedResult = Output('321');
  expectLater(resultFuture, completion(expectedResult));
});

Вот ошибка:

NoSuchMethodError: The method 'send' was called on null.
Receiver: null
Tried calling: send(Instance of 'CrossIsolatesMessage<Input>')
dart:core                                                  Object.noSuchMethod

Почему эта ошибка возникает в тестах? И как правильно писать тесты для этого класса?

1 Ответ

0 голосов
/ 15 июля 2020

Проблема решена.

Создание _isolate и _isolateSendPort является асинхронной операцией c. Вот почему _isolateSendPort на тестах было нулевым. Вызов метода _asyncInit() из Mapper конструктора - неправильный способ создания изолята.

Вот рабочее решение с ленивой инициализацией изолята:

class Mapper {
  SendPort _isolateSendPort;
  Isolate _isolate;

  void _initIsolate() async {
    final receivePort = ReceivePort();
    _isolate = await Isolate.spawn(
      _mappingFunction,
      receivePort.sendPort,
    );
    _isolateSendPort = await receivePort.first;
  }

  ...

  Future<Output> map(Input input) async {
    final port = ReceivePort();
    if (_isolateSendPort == null) {
      await _initIsolate();
    }
    _isolateSendPort.send(CrossIsolatesMessage<Input>(
      sender: port.sendPort,
      message: input,
    ));
    return port.map((event) => event as Output).first;
  }

  ...
}

...