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

时间:2012-12-03 07:36:20

标签: unit-testing dart

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

6 个答案:

答案 0 :(得分: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"]);
    }));
  });
}

使用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();
  }));
}

更新:

自最初询问问题以来,Future和unittest API都已更改。 现在可以从测试函数返回Future,并且unittest通过所有异步保护功能正确执行它。 结合chain then 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();
  });
}

答案 1 :(得分: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})));
  });
}

在此代码完成之前,单元测试运行器可能无法完成。所以看起来单元测试正确执行了。使用Future可能需要更长时间才能完成正确的方法是使用unittest包中提供的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));

人们很想做下面的事情,这是在dart中对返回的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"]);
    });
  });
}

答案 2 :(得分: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);
});

我得到了对未来的引用,并将所有期望的陈述放在then电话中。然后,我注册expect(future, completes)以确保它实际完成。

答案 3 :(得分:3)

请参阅此article中有关异步测试的部分,或expectAsync的API文档。

以下是一个简短的例子。请注意,必须在传递给test()的闭包之前调用expectAsync()。

import 'package:unittest/unittest.dart';

checkProgress() => print('Check progress called.');

main() {
  test('Window timeout test', () {
    var callback = expectAsync(checkProgress);
    new Timer(new Duration(milliseconds:100), callback);
  });
}

在测试期间等待未来完成的另一种方法是将其从传递给测试函数的闭包中返回。请参阅上面链接的文章中的此示例:

import 'dart:async';
import 'package:unittest/unittest.dart';

void main() {
  test('test that time has passed', () {
    var duration = const Duration(milliseconds: 200);
    var time = new DateTime.now();

    return new Future.delayed(duration).then((_) {
      var delta = new DateTime.now().difference(time);

      expect(delta, greaterThanOrEqualTo(duration));
    });
  });
}

答案 4 :(得分:2)

对于mockito v.2 +有可能在

的帮助下完成
await untilCalled(mockObject.someMethod())

答案 5 :(得分:0)

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

  1. 使测试异步
  2. 使用expectexpectLater代替await
  3. 传入将来的方法/获取器,并用completion包装期望值,如下所示:

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

要测试计算总和的方法:

Future<int> getSum(int a,int b) async{
  return a+b;
}

我们可以这样编写测试:

test("test sum",() async{
  await expectLater(getSum(2,3), completion(5));
});