我该如何测试飞镖的未来?

ada*_*ger 22 unit-testing dart

如何测试Future在测试运行器完成之前返回的方法?我有一个问题,我的单元测试运行器在异步方法完成之前完成.

Vad*_*hko 15

另一种可能性是使用expectAsync1函数.初始不正确的测试变体的工作模拟将是:

void main() {
  test("testing a future", () {
    Compute compute = new Compute();
    compute.sumIt([1, 2, 3]).then(expectAsync1((Map m) {
      Expect.equals(true, m.containsKey("value"));
      Expect.equals(6, m["value"]);
    }));
  });
}
Run Code Online (Sandbox Code Playgroud)

使用expectAsync1进行异步测试的一个优点是它的可组合性.有时,测试自然需要几个连续的异步代码块.来自mongo_db的示例测试:

testCursorGetMore(){
  var res;
  Db db = new Db('${DefaultUri}mongo_dart-test');
  DbCollection collection;
  int count = 0;
  Cursor cursor;
  db.open().chain(expectAsync1((c){
    collection = db.collection('new_big_collection2');
    collection.remove();
    return db.getLastError();
  })).chain(expectAsync1((_){
    cursor = new Cursor(db,collection,where.limit(10));
    return cursor.each((v){
     count++;
    });
  })).chain(expectAsync1((dummy){
    expect(count,0);
    List toInsert = new List();
    for (int n=0;n < 1000; n++){
      toInsert.add({"a":n});
    }
    collection.insertAll(toInsert);
    return db.getLastError();
  })).chain(expectAsync1((_){
    cursor = new Cursor(db,collection,where.limit(10));
    return cursor.each((v)=>count++);
  })).then(expectAsync1((v){
    expect(count,1000);
    expect(cursor.cursorId,0);
    expect(cursor.state,Cursor.CLOSED);
    collection.remove();
    db.close();
  }));
}
Run Code Online (Sandbox Code Playgroud)

更新:

自最初询问问题以来,Future和unittest API都已更改.现在可以Future从测试功能返回,并且unittest通过所有异步防护功能正确执行它.结合现在合并的事实chainthen方法,Future为具有多个连续代码块的测试提供了良好的语法.在当前版本的mongo_dart中,相同的测试看起来像:

Future testCursorGetMore(){
  var res;
  Db db = new Db('${DefaultUri}mongo_dart-test');
  DbCollection collection;
  int count = 0;
  Cursor cursor;
  return db.open().then((c){
    collection = db.collection('new_big_collection2');
    collection.remove();
    return db.getLastError();
  }).then((_){
    cursor = new Cursor(db,collection,where.limit(10));
    return cursor.forEach((v){
     count++;
    });
  }).then((dummy){
    expect(count,0);
    List toInsert = new List();
    for (int n=0;n < 1000; n++){
      toInsert.add({"a":n});
    }
    collection.insertAll(toInsert);
    return db.getLastError();
  }).then((_){
    cursor = new Cursor(db,collection,null);
    return cursor.forEach((v)=>count++);
  }).then((v){
    expect(count,1000);
    expect(cursor.cursorId,0);
    expect(cursor.state,State.CLOSED);
    collection.remove();
    return db.close();
  });
}
Run Code Online (Sandbox Code Playgroud)


ada*_*ger 14

如何使用completion匹配器进行测试的完整示例如下.

import 'package:unittest/unittest.dart';

class Compute {
  Future<Map> sumIt(List<int> data) {
    Completer completer = new Completer();
    int sum = 0;
    data.forEach((i) => sum += i);
    completer.complete({"value" : sum});
    return completer.future;
  }
}

void main() {
  test("testing a future", () {
    Compute compute = new Compute();    
    Future<Map> future = compute.sumIt([1, 2, 3]);
    expect(future, completion(equals({"value" : 6})));
  });
}
Run Code Online (Sandbox Code Playgroud)

在此代码完成之前,单元测试运行器可能无法完成.所以看起来单元测试正确执行了.随着Futures表示可能需要更长的时间来完成正确的方法是利用completion在单元测试封装匹配.

/**
 * Matches a [Future] that completes succesfully with a value that matches
 * [matcher]. Note that this creates an asynchronous expectation. The call to
 * `expect()` that includes this will return immediately and execution will
 * continue. Later, when the future completes, the actual expectation will run.
 *
 * To test that a Future completes with an exception, you can use [throws] and
 * [throwsA].
 */
Matcher completion(matcher) => new _Completes(wrapMatcher(matcher));
Run Code Online (Sandbox Code Playgroud)

人们很想做下面的事情,这对于在飞镖中对返回的Future进行单元测试是不正确的.警告:以下是测试期货的错误方法.

import 'package:unittest/unittest.dart';

class Compute {
  Future<Map> sumIt(List<int> data) {
    Completer completer = new Completer();
    int sum = 0;
    data.forEach((i) => sum+=i);
    completer.complete({"value":sum});
    return completer.future;
  }
}

void main() {
  test("testing a future", () {
    Compute compute = new Compute();
    compute.sumIt([1, 2, 3]).then((Map m) {
      Expect.equals(true, m.containsKey("value"));
      Expect.equals(6, m["value"]);
    });
  });
}
Run Code Online (Sandbox Code Playgroud)


Set*_*add 11

作为替代方案,这就是我一直在做的事情.它与上面的答案类似:

test('get by keys', () {
  Future future = asyncSetup().then((_) => store.getByKeys(["hello", "dart"]));
  future.then((values) {
    expect(values, hasLength(2));
    expect(values.contains("world"), true);
    expect(values.contains("is fun"), true);
  });
  expect(future, completes);
});
Run Code Online (Sandbox Code Playgroud)

我得到了对未来的参考,并将所有期待的陈述都放在了then电话中.然后,我注册一个expect(future, completes)以确保它实际完成.


erl*_*man 11

测试返回 Future 的方法的 3 个步骤:

  1. 使测试异步
  2. 而不是expect使用expectLaterawaitit。
  3. 传入 future 方法/getter 并用completion如下方式包装预期值:

await expectLater(getSum(2,3), completion(5));

测试计算总和的方法:

Future<int> getSum(int a,int b) async{
  return a+b;
}
Run Code Online (Sandbox Code Playgroud)

我们可以这样编写测试:

test("test sum",() async{
  await expectLater(getSum(2,3), completion(5));
});
Run Code Online (Sandbox Code Playgroud)