为什么在这个单元测试期间没有使用dart进程退出:io?

时间:2015-01-26 21:24:41

标签: debugging dart

以下代码测试客户端发送的服务器上的接收数据。

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:unittest/unittest.dart';

main() {
  ServerSocket ss;

  setUp(() => ServerSocket.bind('localhost', 9876).then((e) => ss = e));

  tearDown(() => ss.close());

  test('test 1', () {
    final line = new Completer<String>();
    ss.listen((s) => s.map(UTF8.decode).listen((s) => line.complete(s)));
    Socket.connect(ss.address, ss.port)
        .then((s) {
          s.write('test');
          return s.close();
        })
        .then((_) => line.future)
        .then(expectAsync((s) => expect(s, equals('test'))));
  });
}

此测试显示:

unittest-suite-wait-for-done
PASS: test 1

All 1 tests passed.
unittest-suite-success

然而,这个过程并没有停止。

  1. 为什么即使使用ss.close()s.close()
  2. ,流程仍在运行
  3. 如何找到使该过程保持活力的原因? Observatory是否提供了调试的内容?

2 个答案:

答案 0 :(得分:3)

编辑:请参阅下面的亚历克斯答案。 Socket.drain()FTW!

根据observatory io page,服务器创建的套接字仍然可以写入。我已更新下面的代码,在服务器和客户端套接字上调用destroy()destroy()向两个方向关闭Socket

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:unittest/unittest.dart';

main() {
  ServerSocket ss;

  setUp(() => ServerSocket.bind('localhost', 9876).then((e) => ss = e));

  tearDown(() => ss.close());

  test('test 1', () {
    final line = new Completer<String>();
    ss.listen((s) {
      s.map(UTF8.decode).listen((t) {
        line.complete(t);
        s.destroy();
      });
    });
    Socket.connect(ss.address, ss.port)
        .then((s) {
          s.write('test');
          return s.flush().then((_) {
            s.destroy();
            return line.future;
          });
        })
        .then(expectAsync((s) => expect(s, equals('test'))));
  });
}

答案 1 :(得分:1)

根据William comment on the answer of Greg drain()close()应该首选,而不是destroy()

以下是工作版本:

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:unittest/unittest.dart';

main() {
  ServerSocket ss;

  setUp(() => ServerSocket.bind('localhost', 9876).then((e) => ss = e));

  tearDown(() => ss.close());

  test('test 1', () {
    final line = new Completer<String>();
    ss.listen((s) => UTF8.decodeStream(s)
                         .then((value) => line.complete(value))
                         .then((_)=> s.close()));
    Socket.connect(ss.address, ss.port)
        .then((s) {
          s.write('test');
          return Future.wait([s.drain(), s.close()]);
        })
        .then((_) => line.future)
        .then(expectAsync((s) => expect(s, equals('test'))));
  });
}

对此有一些评论:

  • 在服务器端我使用UTF8.decodeStream(s).then(...)而不是s.map(UTF8.decode).listen(...),因为该值可以分成几个块。在这种情况下,套接字会更早关闭。
  • 在客户端我使用Future.wait([s.drain(), s.close()])而不是链接Futures。如果我使用s.drain().then((_) => s.close())进程阻塞,因为服务器正在等待数据流的结束(在客户端由s.close()触发)关闭Socket,从而触发s.drain()的完成在客户端。